diff --git a/src/doc/reference.md b/src/doc/reference.md index 31524579df7..781b40be768 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -731,15 +731,20 @@ Rust syntax is restricted in two ways: pairs when they occur at the beginning of, or immediately after, a `$(...)*`; requiring a distinctive token in front can solve the problem. -## Syntax extensions useful for the macro author +## Syntax extensions useful in macros + +* `stringify!` : turn the identifier argument into a string literal +* `concat!` : concatenates a comma-separated list of literals + +## Syntax extensions for macro debugging * `log_syntax!` : print out the arguments at compile time * `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging -* `stringify!` : turn the identifier argument into a string literal -* `concat!` : concatenates a comma-separated list of literals -* `concat_idents!` : create a new identifier by concatenating the arguments -The following attributes are used for quasiquoting in procedural macros: +## Quasiquoting + +The following syntax extensions are used for quasiquoting Rust syntax trees, +usually in [procedural macros](book/plugins.html#syntax-extensions): * `quote_expr!` * `quote_item!` @@ -748,6 +753,8 @@ The following attributes are used for quasiquoting in procedural macros: * `quote_tokens!` * `quote_ty!` +Documentation is very limited at the moment. + # Crates and source files Rust is a *compiled* language. Its semantics obey a *phase distinction* diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md index aff365051a4..a226e4d0bf9 100644 --- a/src/doc/trpl/advanced-macros.md +++ b/src/doc/trpl/advanced-macros.md @@ -192,19 +192,58 @@ To keep this system simple and correct, `#[macro_use] extern crate ...` may only appear at the root of your crate, not inside `mod`. This ensures that `$crate` is a single identifier. -# A final note +# The deep end -Macros, as currently implemented, are not for the faint of heart. Even -ordinary syntax errors can be more difficult to debug when they occur inside a -macro, and errors caused by parse problems in generated code can be very -tricky. Invoking the `log_syntax!` macro can help elucidate intermediate -states, invoking `trace_macros!(true)` will automatically print those -intermediate states out, and passing the flag `--pretty expanded` as a -command-line argument to the compiler will show the result of expansion. +The introductory chapter mentioned recursive macros, but it did not give the +full story. Recursive macros are useful for another reason: Each recursive +invocation gives you another opportunity to pattern-match the macro's +arguments. + +As an extreme example, it is possible, though hardly advisable, to implement +the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton +within Rust's macro system. + +```rust +#![feature(trace_macros)] + +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} + +fn main() { + trace_macros!(true); +# /* just check the definition + bct!(0, 0, 1, 1, 1 ; 1, 0, 1); +# */ +} +``` + +Exercise: use macros to reduce duplication in the above definition of the +`bct!` macro. + +# Procedural macros If Rust's macro system can't do what you need, you may want to write a [compiler plugin](plugins.html) instead. Compared to `macro_rules!` macros, this is significantly more work, the interfaces are much less stable, -and the warnings about debugging apply ten-fold. In exchange you get the +and bugs can be much harder to track down. In exchange you get the flexibility of running arbitrary Rust code within the compiler. Syntax extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index 49da298bb3f..7da36043f6c 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -189,14 +189,12 @@ shorthand for a data type could be valid as either an expression or a pattern. ## Repetition -The repetition behavior can seem somewhat magical, especially when multiple -names are bound at multiple nested levels of repetition. The two rules to keep -in mind are: +The repetition operator follows two principal rules: -1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for -all of the `$name`s it contains, in lockstep, and +1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s + it contains, in lockstep, and 2. each `$name` must be under at least as many `$(...)*`s as it was matched -against. If it is under more, it'll be duplicated, as appropriate. + against. If it is under more, it'll be duplicated, as appropriate. This baroque macro illustrates the duplication of variables from outer repetition levels. @@ -226,6 +224,10 @@ That's most of the matcher syntax. These examples use `$(...)*`, which is a more" match. Both forms optionally include a separator, which can be any token except `+` or `*`. +This system is based on +"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)" +(PDF link). + # Hygiene Some languages implement macros using simple text substitution, which leads to @@ -273,19 +275,26 @@ macro, using [a GNU C extension] to emulate Rust's expression blocks. }) ``` -This looks reasonable, but watch what happens in this example: +Here's a simple use case that goes terribly wrong: ```text const char *state = "reticulating splines"; -LOG(state); +LOG(state) ``` -The program will likely segfault, after it tries to execute +This expands to ```text -printf("log(%d): %s\n", state, state); +const char *state = "reticulating splines"; +int state = get_log_state(); +if (state > 0) { + printf("log(%d): %s\n", state, state); +} ``` +The second variable named `state` shadows the first one. This is a problem +because the print statement should refer to both of them. + The equivalent Rust macro has the desired behavior. ```rust @@ -357,6 +366,64 @@ fn main() { [items]: ../reference.html#items +# Recursive macros + +A macro's expansion can include more macro invocations, including invocations +of the very same macro being expanded. These recursive macros are useful for +processing tree-structured input, as illustrated by this (simplistic) HTML +shorthand: + +```rust +# #![allow(unused_must_use)] +macro_rules! write_html { + ($w:expr, ) => (()); + + ($w:expr, $e:tt) => (write!($w, "{}", $e)); + + ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{ + write!($w, "<{}>", stringify!($tag)); + write_html!($w, $($inner)*); + write!($w, "", stringify!($tag)); + write_html!($w, $($rest)*); + }}; +} + +fn main() { +# // FIXME(#21826) + use std::fmt::Write; + let mut out = String::new(); + + write_html!(&mut out, + html[ + head[title["Macros guide"]] + body[h1["Macros are the best!"]] + ]); + + assert_eq!(out, + "Macros guide\ +

Macros are the best!

"); +} +``` + +# Debugging macro code + +To see the results of expanding macros, run `rustc --pretty expanded`. The +output represents a whole crate, so you can also feed it back in to `rustc`, +which will sometimes produce better error messages than the original +compilation. Note that the `--pretty expanded` output may have a different +meaning if multiple variables of the same name (but different syntax contexts) +are in play in the same scope. In this case `--pretty expanded,hygiene` will +tell you about the syntax contexts. + +`rustc` provides two syntax extensions that help with macro debugging. For now, +they are unstable and require feature gates. + +* `log_syntax!(...)` will print its arguments to standard output, at compile + time, and "expand" to nothing. + +* `trace_macros!(true)` will enable a compiler message every time a macro is + expanded. Use `trace_macros!(false)` later in expansion to turn it off. + # Further reading The [advanced macros chapter][] goes into more detail about macro syntax. It diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index 79502f3cd17..f609a0a918a 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -146,14 +146,7 @@ a more involved macro example, see ## Tips and tricks -To see the results of expanding syntax extensions, run -`rustc --pretty expanded`. The output represents a whole crate, so you -can also feed it back in to `rustc`, which will sometimes produce better -error messages than the original compilation. Note that the -`--pretty expanded` output may have a different meaning if multiple -variables of the same name (but different syntax contexts) are in play -in the same scope. In this case `--pretty expanded,hygiene` will tell -you about the syntax contexts. +Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable. You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into higher-level syntax elements like expressions: @@ -184,6 +177,11 @@ and return [`DummyResult`](../syntax/ext/base/struct.DummyResult.html), so that the compiler can continue and find further errors. +To print syntax fragments for debugging, you can use +[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together +with +[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions). + The example above produced an integer literal using [`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint). As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6850e8c0f8e..ca27ec9d3bb 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -790,7 +790,7 @@ pub trait SliceExt { fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; /// Convert `self` into a vector without clones or allocation. - #[unstable(feature = "collections")] + #[stable(feature = "rust1", since = "1.0.0")] fn into_vec(self: Box) -> Vec; } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 6d8e04d97dd..b4ccf930437 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -981,7 +981,7 @@ pub trait IteratorExt: Iterator + Sized { #[unstable(feature = "core", reason = "recent addition")] fn cloned(self) -> Cloned where Self::Item: Deref, - ::Output: Clone, + ::Target: Clone, { Cloned { it: self } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 9b5e94e87a1..a4f69e651df 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -405,8 +405,8 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { - fn check_def(&mut self, sp: Span, ty_id: ast::NodeId, path_id: ast::NodeId) { - match self.cx.tcx.def_map.borrow()[path_id].clone() { + fn check_def(&mut self, sp: Span, id: ast::NodeId) { + match self.cx.tcx.def_map.borrow()[id].full_def() { def::DefPrimTy(ast::TyInt(ast::TyIs(_))) => { self.cx.span_lint(IMPROPER_CTYPES, sp, "found rust type `isize` in foreign module, while \ @@ -418,7 +418,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { libc::c_uint or libc::c_ulong should be used"); } def::DefTy(..) => { - let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&ty_id) { + let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) { Some(&ty::atttce_resolved(t)) => t, _ => panic!("ast_ty_to_ty_cache was incomplete after typeck!") }; @@ -437,9 +437,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { - match ty.node { - ast::TyPath(_, id) => self.check_def(ty.span, ty.id, id), - _ => (), + if let ast::TyPath(..) = ty.node { + self.check_def(ty.span, ty.id); } visit::walk_ty(self, ty); } @@ -683,8 +682,8 @@ impl LintPass for PathStatements { match s.node { ast::StmtSemi(ref expr, _) => { match expr.node { - ast::ExprPath(_) => cx.span_lint(PATH_STATEMENTS, s.span, - "path statement with no effect"), + ast::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span, + "path statement with no effect"), _ => () } } @@ -1001,7 +1000,8 @@ impl LintPass for NonSnakeCase { fn check_pat(&mut self, cx: &Context, p: &ast::Pat) { if let &ast::PatIdent(_, ref path1, _) = &p.node { - if let Some(&def::DefLocal(_)) = cx.tcx.def_map.borrow().get(&p.id) { + let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); + if let Some(def::DefLocal(_)) = def { self.check_snake_case(cx, "variable", path1.node, p.span); } } @@ -1066,8 +1066,8 @@ impl LintPass for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &Context, p: &ast::Pat) { // Lint for constants that look like binding identifiers (#7526) - match (&p.node, cx.tcx.def_map.borrow().get(&p.id)) { - (&ast::PatIdent(_, ref path1, _), Some(&def::DefConst(..))) => { + match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) { + (&ast::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", path1.node, p.span); } @@ -1227,10 +1227,13 @@ impl LintPass for NonShorthandFieldPatterns { fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) { let def_map = cx.tcx.def_map.borrow(); if let ast::PatStruct(_, ref v, _) = pat.node { - for fieldpat in v.iter() - .filter(|fieldpat| !fieldpat.node.is_shorthand) - .filter(|fieldpat| def_map.get(&fieldpat.node.pat.id) - == Some(&def::DefLocal(fieldpat.node.pat.id))) { + let field_pats = v.iter() + .filter(|fieldpat| !fieldpat.node.is_shorthand) + .filter(|fieldpat| { + let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def()); + def == Some(def::DefLocal(fieldpat.node.pat.id)) + }); + for fieldpat in field_pats { if let ast::PatIdent(_, ident, None) = fieldpat.node.pat.node { if ident.node.as_str() == fieldpat.node.ident.as_str() { cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, @@ -1899,10 +1902,7 @@ impl LintPass for UnconditionalRecursion { _: ast::Ident, id: ast::NodeId) -> bool { tcx.def_map.borrow().get(&id) - .map_or(false, |def| { - let did = def.def_id(); - ast_util::is_local(did) && did.node == fn_id - }) + .map_or(false, |def| def.def_id() == ast_util::local_def(fn_id)) } // check if the method call `id` refers to method `method_id` diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 5ee2f890189..f5c4cce0659 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -150,12 +150,9 @@ pub fn get_trait_name(cstore: &cstore::CStore, def: ast::DefId) -> ast::Name { def.node) } -pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId) - -> (ast::Name, def::TraitItemKind) { +pub fn is_static_method(cstore: &cstore::CStore, def: ast::DefId) -> bool { let cdata = cstore.get_crate_data(def.krate); - decoder::get_trait_item_name_and_kind(cstore.intr.clone(), - &*cdata, - def.node) + decoder::is_static_method(&*cdata, def.node) } pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: ast::DefId) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index aeae101a123..0503045ac6e 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -119,7 +119,6 @@ enum Family { StaticMethod, // F Method, // h Type, // y - ForeignType, // T Mod, // m ForeignMod, // n Enum, // t @@ -145,7 +144,6 @@ fn item_family(item: rbml::Doc) -> Family { 'F' => StaticMethod, 'h' => Method, 'y' => Type, - 'T' => ForeignType, 'm' => Mod, 'n' => ForeignMod, 't' => Enum, @@ -174,16 +172,13 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility { } } -fn item_sort(item: rbml::Doc) -> char { +fn item_sort(item: rbml::Doc) -> Option { let mut ret = None; reader::tagged_docs(item, tag_item_trait_item_sort, |doc| { ret = Some(doc.as_str_slice().as_bytes()[0] as char); false }); - match ret { - Some(r) => r, - None => panic!("No item_sort found") - } + ret } fn item_symbol(item: rbml::Doc) -> String { @@ -339,14 +334,16 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) def::FromImpl(item_reqd_and_translated_parent_item(cnum, item)) }; - match fam { - // We don't bother to get encode/decode the trait id, we don't need it. - Method => DlDef(def::DefMethod(did, None, provenance)), - StaticMethod => DlDef(def::DefStaticMethod(did, provenance)), - _ => panic!() + DlDef(def::DefMethod(did, provenance)) + } + Type => { + if item_sort(item) == Some('t') { + let trait_did = item_reqd_and_translated_parent_item(cnum, item); + DlDef(def::DefAssociatedTy(trait_did, did)) + } else { + DlDef(def::DefTy(did, false)) } } - Type | ForeignType => DlDef(def::DefTy(did, false)), Mod => DlDef(def::DefMod(did)), ForeignMod => DlDef(def::DefForeignMod(did)), StructVariant => { @@ -357,7 +354,7 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) let enum_did = item_reqd_and_translated_parent_item(cnum, item); DlDef(def::DefVariant(enum_did, did, false)) } - Trait => DlDef(def::DefaultImpl(did)), + Trait => DlDef(def::DefTrait(did)), Enum => DlDef(def::DefTy(did, true)), Impl | DefaultImpl => DlImpl(did), PublicField | InheritedField => DlField, @@ -831,8 +828,10 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId) tag_item_impl_item, |doc| { let def_id = item_def_id(doc, cdata); match item_sort(doc) { - 'r' | 'p' => impl_items.push(ty::MethodTraitItemId(def_id)), - 't' => impl_items.push(ty::TypeTraitItemId(def_id)), + Some('r') | Some('p') => { + impl_items.push(ty::MethodTraitItemId(def_id)) + } + Some('t') => impl_items.push(ty::TypeTraitItemId(def_id)), _ => panic!("unknown impl item sort"), } true @@ -849,22 +848,13 @@ pub fn get_trait_name(intr: Rc, item_name(&*intr, doc) } -pub fn get_trait_item_name_and_kind(intr: Rc, - cdata: Cmd, - id: ast::NodeId) - -> (ast::Name, def::TraitItemKind) { +pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool { let doc = lookup_item(id, cdata.data()); - let name = item_name(&*intr, doc); match item_sort(doc) { - 'r' | 'p' => { - let explicit_self = get_explicit_self(doc); - (name, def::TraitItemKind::from_explicit_self_category(explicit_self)) - } - 't' => (name, def::TypeTraitItemKind), - c => { - panic!("get_trait_item_name_and_kind(): unknown trait item kind \ - in metadata: `{}`", c) + Some('r') | Some('p') => { + get_explicit_self(doc) == ty::StaticExplicitSelfCategory } + _ => false } } @@ -889,7 +879,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, let vis = item_visibility(method_doc); match item_sort(method_doc) { - 'r' | 'p' => { + Some('r') | Some('p') => { let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics); let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics); let fty = doc_method_fty(method_doc, tcx, cdata); @@ -906,7 +896,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, container, provided_source))) } - 't' => { + Some('t') => { ty::TypeTraitItem(Rc::new(ty::AssociatedType { name: name, vis: vis, @@ -926,8 +916,10 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId) reader::tagged_docs(item, tag_item_trait_item, |mth| { let def_id = item_def_id(mth, cdata); match item_sort(mth) { - 'r' | 'p' => result.push(ty::MethodTraitItemId(def_id)), - 't' => result.push(ty::TypeTraitItemId(def_id)), + Some('r') | Some('p') => { + result.push(ty::MethodTraitItemId(def_id)); + } + Some('t') => result.push(ty::TypeTraitItemId(def_id)), _ => panic!("unknown trait item sort"), } true @@ -956,7 +948,7 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc, let did = item_def_id(mth_id, cdata); let mth = lookup_item(did.node, data); - if item_sort(mth) == 'p' { + if item_sort(mth) == Some('p') { let trait_item = get_impl_or_trait_item(intr.clone(), cdata, did.node, @@ -1560,7 +1552,7 @@ pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items); match maybe_find_item(id, items) { None => false, - Some(item) => item_sort(item) == 't', + Some(item) => item_sort(item) == Some('t'), } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index e0832bb683a..ee2745ca66b 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1193,7 +1193,7 @@ fn encode_info_for_item(ecx: &EncodeContext, None => {} } } - ast::ItemDefaultImpl(unsafety, ref ast_trait_ref) => { + ast::ItemDefaultImpl(unsafety, _) => { add_to_index(item, rbml_w, index); rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); @@ -1201,7 +1201,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(rbml_w, item.ident.name); encode_unsafety(rbml_w, unsafety); - let trait_ref = ty::node_id_to_trait_ref(tcx, ast_trait_ref.ref_id); + let trait_ref = ty::impl_id_to_trait_ref(tcx, item.id); encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref); rbml_w.end_tag(); } @@ -1221,7 +1221,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_unsafety(rbml_w, unsafety); encode_polarity(rbml_w, polarity); match ty.node { - ast::TyPath(ref path, _) if path.segments.len() == 1 => { + ast::TyPath(None, ref path) if path.segments.len() == 1 => { let ident = path.segments.last().unwrap().identifier; encode_impl_type_basename(rbml_w, ident); } @@ -1241,9 +1241,8 @@ fn encode_info_for_item(ecx: &EncodeContext, } rbml_w.end_tag(); } - if let Some(ref ast_trait_ref) = *opt_trait { - let trait_ref = ty::node_id_to_trait_ref( - tcx, ast_trait_ref.ref_id); + if opt_trait.is_some() { + let trait_ref = ty::impl_id_to_trait_ref(tcx, item.id); encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref); } encode_path(rbml_w, path.clone()); @@ -1871,9 +1870,7 @@ struct ImplVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> { fn visit_item(&mut self, item: &ast::Item) { if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node { - let def_map = &self.ecx.tcx.def_map; - let trait_def = def_map.borrow()[trait_ref.ref_id].clone(); - let def_id = trait_def.def_id(); + let def_id = self.ecx.tcx.def_map.borrow()[trait_ref.ref_id].def_id(); // Load eagerly if this is an implementation of the Drop trait // or if the trait is not defined in this crate. diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index d699ba40e82..17fd80ceaea 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -22,68 +22,58 @@ use util::ppaux::Repr; pub const NO_REGIONS: uint = 1; pub const NO_TPS: uint = 2; -pub fn check_path_args(tcx: &ty::ctxt, - path: &ast::Path, - flags: uint) { - if (flags & NO_TPS) != 0 { - if path.segments.iter().any(|s| s.parameters.has_types()) { - span_err!(tcx.sess, path.span, E0109, - "type parameters are not allowed on this type"); +pub fn check_path_args(tcx: &ty::ctxt, segments: &[ast::PathSegment], flags: uint) { + for segment in segments { + if (flags & NO_TPS) != 0 { + for typ in segment.parameters.types() { + span_err!(tcx.sess, typ.span, E0109, + "type parameters are not allowed on this type"); + break; + } + } + + if (flags & NO_REGIONS) != 0 { + for lifetime in segment.parameters.lifetimes() { + span_err!(tcx.sess, lifetime.span, E0110, + "lifetime parameters are not allowed on this type"); + break; + } } } +} - if (flags & NO_REGIONS) != 0 { - if path.segments.iter().any(|s| s.parameters.has_lifetimes()) { - span_err!(tcx.sess, path.span, E0110, - "region parameters are not allowed on this type"); - } +pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>, + segments: &[ast::PathSegment], + nty: ast::PrimTy) + -> Ty<'tcx> { + check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + match nty { + ast::TyBool => tcx.types.bool, + ast::TyChar => tcx.types.char, + ast::TyInt(it) => ty::mk_mach_int(tcx, it), + ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit), + ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft), + ast::TyStr => ty::mk_str(tcx) } } pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) -> Option> { - match ast_ty.node { - ast::TyPath(ref path, id) => { - let a_def = match tcx.def_map.borrow().get(&id) { - None => { - tcx.sess.span_bug(ast_ty.span, - &format!("unbound path {}", - path.repr(tcx))) - } - Some(&d) => d - }; - match a_def { - def::DefPrimTy(nty) => { - match nty { - ast::TyBool => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(tcx.types.bool) - } - ast::TyChar => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(tcx.types.char) - } - ast::TyInt(it) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_mach_int(tcx, it)) - } - ast::TyUint(uit) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_mach_uint(tcx, uit)) - } - ast::TyFloat(ft) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_mach_float(tcx, ft)) - } - ast::TyStr => { - Some(ty::mk_str(tcx)) - } - } - } - _ => None + if let ast::TyPath(None, ref path) = ast_ty.node { + let def = match tcx.def_map.borrow().get(&ast_ty.id) { + None => { + tcx.sess.span_bug(ast_ty.span, + &format!("unbound path {}", path.repr(tcx))) } + Some(d) => d.full_def() + }; + if let def::DefPrimTy(nty) = def { + Some(prim_ty_to_ty(tcx, &path.segments[], nty)) + } else { + None } - _ => None + } else { + None } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index e63901c21b2..5983829ed8f 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -25,6 +25,7 @@ use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; use middle::check_const::ConstQualif; use middle::mem_categorization::Typer; +use middle::privacy::{AllPublic, LastMod}; use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin}; @@ -423,13 +424,8 @@ impl tr for def::Def { fn tr(&self, dcx: &DecodeContext) -> def::Def { match *self { def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor), - def::DefStaticMethod(did, p) => { - def::DefStaticMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) - } - def::DefMethod(did0, did1, p) => { - def::DefMethod(did0.tr(dcx), - did1.map(|did1| did1.tr(dcx)), - p.map(|did2| did2.tr(dcx))) + def::DefMethod(did, p) => { + def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) } def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) } def::DefMod(did) => { def::DefMod(did.tr(dcx)) } @@ -440,13 +436,10 @@ impl tr for def::Def { def::DefVariant(e_did, v_did, is_s) => { def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s) }, - def::DefaultImpl(did) => def::DefaultImpl(did.tr(dcx)), + def::DefTrait(did) => def::DefTrait(did.tr(dcx)), def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum), - def::DefAssociatedTy(did) => def::DefAssociatedTy(did.tr(dcx)), - def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) => - def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did.tr(dcx)), ident), - def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) => - def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident), + def::DefAssociatedTy(trait_did, did) => + def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)), def::DefPrimTy(p) => def::DefPrimTy(p), def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n), def::DefUse(did) => def::DefUse(did.tr(dcx)), @@ -455,9 +448,6 @@ impl tr for def::Def { } def::DefStruct(did) => def::DefStruct(did.tr(dcx)), def::DefRegion(nid) => def::DefRegion(dcx.tr_id(nid)), - def::DefTyParamBinder(nid) => { - def::DefTyParamBinder(dcx.tr_id(nid)) - } def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)) } } @@ -1159,10 +1149,10 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, debug!("Encoding side tables for id {}", id); - if let Some(def) = tcx.def_map.borrow().get(&id) { + if let Some(def) = tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { rbml_w.tag(c::tag_table_def, |rbml_w| { rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| (*def).encode(rbml_w).unwrap()); + rbml_w.tag(c::tag_table_val, |rbml_w| def.encode(rbml_w).unwrap()); }) } @@ -1862,7 +1852,12 @@ fn decode_side_tables(dcx: &DecodeContext, match value { c::tag_table_def => { let def = decode_def(dcx, val_doc); - dcx.tcx.def_map.borrow_mut().insert(id, def); + dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution { + base_def: def, + // This doesn't matter cross-crate. + last_private: LastMod(AllPublic), + depth: 0 + }); } c::tag_table_node_type => { let ty = val_dsr.read_ty(dcx); diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 52eedc460eb..24c54b53590 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -398,8 +398,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { ast::ExprMac(..) | ast::ExprClosure(..) | ast::ExprLit(..) | - ast::ExprPath(..) | - ast::ExprQPath(..) => { + ast::ExprPath(..) => { self.straightline(expr, pred, None::.iter()) } } @@ -610,32 +609,24 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn find_scope(&self, expr: &ast::Expr, label: Option) -> LoopScope { - match label { - None => { - return *self.loop_scopes.last().unwrap(); - } + if label.is_none() { + return *self.loop_scopes.last().unwrap(); + } - Some(_) => { - match self.tcx.def_map.borrow().get(&expr.id) { - Some(&def::DefLabel(loop_id)) => { - for l in &self.loop_scopes { - if l.loop_id == loop_id { - return *l; - } - } - self.tcx.sess.span_bug( - expr.span, - &format!("no loop scope for id {}", - loop_id)); - } - - r => { - self.tcx.sess.span_bug( - expr.span, - &format!("bad entry `{:?}` in def_map for label", - r)); + match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) { + Some(def::DefLabel(loop_id)) => { + for l in &self.loop_scopes { + if l.loop_id == loop_id { + return *l; } } + self.tcx.sess.span_bug(expr.span, + &format!("no loop scope for id {}", loop_id)); + } + + r => { + self.tcx.sess.span_bug(expr.span, + &format!("bad entry `{:?}` in def_map for label", r)); } } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index f1c8ad94764..8401d25024d 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -439,8 +439,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } } - ast::ExprPath(_) | ast::ExprQPath(_) => { - let def = v.tcx.def_map.borrow().get(&e.id).cloned(); + ast::ExprPath(..) => { + let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); match def { Some(def::DefVariant(_, _, _)) => { // Count the discriminator or function pointer. @@ -452,8 +452,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, v.add_qualif(NON_ZERO_SIZED); } } - Some(def::DefFn(..)) | - Some(def::DefStaticMethod(..)) | Some(def::DefMethod(..)) => { + Some(def::DefFn(..)) | Some(def::DefMethod(..)) => { // Count the function pointer. v.add_qualif(NON_ZERO_SIZED); } @@ -500,7 +499,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, _ => break }; } - let def = v.tcx.def_map.borrow().get(&callee.id).cloned(); + let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); match def { Some(def::DefStruct(..)) => {} Some(def::DefVariant(..)) => { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 7bd64a4f487..c409c8fb13f 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -242,7 +242,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => { let pat_ty = ty::pat_ty(cx.tcx, p); if let ty::ty_enum(def_id, _) = pat_ty.sty { - let def = cx.tcx.def_map.borrow().get(&p.id).cloned(); + let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(DefLocal(_)) = def { if ty::enum_variants(cx.tcx, def_id).iter().any(|variant| token::get_name(variant.name) == token::get_name(ident.node.name) @@ -434,7 +434,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { fn fold_pat(&mut self, pat: P) -> P { return match pat.node { ast::PatIdent(..) | ast::PatEnum(..) => { - let def = self.tcx.def_map.borrow().get(&pat.id).cloned(); + let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()); match def { Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) { Some(const_expr) => { @@ -733,28 +733,28 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, let pat = raw_pat(p); match pat.node { ast::PatIdent(..) => - match cx.tcx.def_map.borrow().get(&pat.id) { - Some(&DefConst(..)) => + match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefConst(..)) => cx.tcx.sess.span_bug(pat.span, "const pattern should've \ been rewritten"), - Some(&DefStruct(_)) => vec!(Single), - Some(&DefVariant(_, id, _)) => vec!(Variant(id)), + Some(DefStruct(_)) => vec!(Single), + Some(DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!() }, ast::PatEnum(..) => - match cx.tcx.def_map.borrow().get(&pat.id) { - Some(&DefConst(..)) => + match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefConst(..)) => cx.tcx.sess.span_bug(pat.span, "const pattern should've \ been rewritten"), - Some(&DefVariant(_, id, _)) => vec!(Variant(id)), + Some(DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!(Single) }, ast::PatStruct(..) => - match cx.tcx.def_map.borrow().get(&pat.id) { - Some(&DefConst(..)) => + match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefConst(..)) => cx.tcx.sess.span_bug(pat.span, "const pattern should've \ been rewritten"), - Some(&DefVariant(_, id, _)) => vec!(Variant(id)), + Some(DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!(Single) }, ast::PatLit(ref expr) => @@ -847,7 +847,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], Some(repeat(DUMMY_WILD_PAT).take(arity).collect()), ast::PatIdent(_, _, _) => { - let opt_def = cx.tcx.def_map.borrow().get(&pat_id).cloned(); + let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def()); match opt_def { Some(DefConst(..)) => cx.tcx.sess.span_bug(pat_span, "const pattern should've \ @@ -862,7 +862,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } ast::PatEnum(_, ref args) => { - let def = cx.tcx.def_map.borrow()[pat_id].clone(); + let def = cx.tcx.def_map.borrow()[pat_id].full_def(); match def { DefConst(..) => cx.tcx.sess.span_bug(pat_span, "const pattern should've \ @@ -880,7 +880,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], ast::PatStruct(_, ref pattern_fields, _) => { // Is this a struct or an enum variant? - let def = cx.tcx.def_map.borrow()[pat_id].clone(); + let def = cx.tcx.def_map.borrow()[pat_id].full_def(); let class_id = match def { DefConst(..) => cx.tcx.sess.span_bug(pat_span, "const pattern should've \ diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 4280b7fe3f0..b97978fc03f 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -93,10 +93,10 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { - match self.def_map.borrow().get(&e.id) { - Some(&DefStatic(def_id, _)) | - Some(&DefConst(def_id)) if + ast::ExprPath(..) => { + match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { + Some(DefStatic(def_id, _)) | + Some(DefConst(def_id)) if ast_util::is_local(def_id) => { match self.ast_map.get(def_id.node) { ast_map::NodeItem(item) => diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 5bf7422dbc0..f793d3ce2fb 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -31,7 +31,7 @@ use std::{i8, i16, i32, i64}; use std::rc::Rc; fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> { - let opt_def = tcx.def_map.borrow().get(&e.id).cloned(); + let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); match opt_def { Some(def::DefConst(def_id)) => { lookup_const_by_id(tcx, def_id) @@ -148,11 +148,11 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P ast::PatTup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect()), ast::ExprCall(ref callee, ref args) => { - let def = tcx.def_map.borrow()[callee.id].clone(); + let def = tcx.def_map.borrow()[callee.id]; if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) { entry.insert(def); } - let path = match def { + let path = match def.full_def() { def::DefStruct(def_id) => def_to_path(tcx, def_id), def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did), _ => unreachable!() @@ -178,8 +178,8 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P ast::PatVec(pats, None, vec![]) } - ast::ExprPath(ref path) => { - let opt_def = tcx.def_map.borrow().get(&expr.id).cloned(); + ast::ExprPath(_, ref path) => { + let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()); match opt_def { Some(def::DefStruct(..)) => ast::PatStruct(path.clone(), vec![], false), @@ -194,13 +194,6 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P } } - ast::ExprQPath(_) => { - match lookup_const(tcx, expr) { - Some(actual) => return const_expr_to_pat(tcx, actual, span), - _ => unreachable!() - } - } - _ => ast::PatLit(P(expr.clone())) }; P(ast::Pat { id: expr.id, node: pat, span: span }) @@ -388,8 +381,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint))); cast_const(val, ety) } - ast::ExprPath(_) | ast::ExprQPath(_) => { - let opt_def = tcx.def_map.borrow().get(&e.id).cloned(); + ast::ExprPath(..) => { + let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); let (const_expr, const_ty) = match opt_def { Some(def::DefConst(def_id)) => { if ast_util::is_local(def_id) { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index ff78deb8d12..2d837ce52b5 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -71,13 +71,13 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) { self.tcx.def_map.borrow().get(id).map(|def| { - match def { - &def::DefConst(_) => { + match def.full_def() { + def::DefConst(_) => { self.check_def_id(def.def_id()) } _ if self.ignore_non_const_paths => (), - &def::DefPrimTy(_) => (), - &def::DefVariant(enum_id, variant_id, _) => { + def::DefPrimTy(_) => (), + def::DefVariant(enum_id, variant_id, _) => { self.check_def_id(enum_id); self.check_def_id(variant_id); } @@ -158,7 +158,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[codemap::Spanned]) { - let id = match (*self.tcx.def_map.borrow())[lhs.id] { + let id = match self.tcx.def_map.borrow()[lhs.id].full_def() { def::DefVariant(_, id, _) => id, _ => { match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 009bfaf8728..1a054c0f464 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -10,10 +10,9 @@ pub use self::Def::*; pub use self::MethodProvenance::*; -pub use self::TraitItemKind::*; +use middle::privacy::LastPrivate; use middle::subst::ParamSpace; -use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory}; use util::nodemap::NodeMap; use syntax::ast; use syntax::ast_util::local_def; @@ -23,7 +22,6 @@ use std::cell::RefCell; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { DefFn(ast::DefId, bool /* is_ctor */), - DefStaticMethod(/* method */ ast::DefId, MethodProvenance), DefSelfTy(/* trait id */ ast::NodeId), DefMod(ast::DefId), DefForeignMod(ast::DefId), @@ -32,13 +30,8 @@ pub enum Def { DefLocal(ast::NodeId), DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */), DefTy(ast::DefId, bool /* is_enum */), - DefAssociatedTy(ast::DefId), - // A partially resolved path to an associated type `T::U` where `T` is a concrete - // type (indicated by the DefId) which implements a trait which has an associated - // type `U` (indicated by the Ident). - // FIXME(#20301) -- should use Name - DefAssociatedPath(TyParamProvenance, ast::Ident), - DefaultImpl(ast::DefId), + DefAssociatedTy(ast::DefId /* trait */, ast::DefId), + DefTrait(ast::DefId), DefPrimTy(ast::PrimTy), DefTyParam(ParamSpace, u32, ast::DefId, ast::Name), DefUse(ast::DefId), @@ -54,14 +47,48 @@ pub enum Def { /// - If it's an ExprPath referring to some tuple struct, then DefMap maps /// it to a def whose id is the StructDef.ctor_id. DefStruct(ast::DefId), - DefTyParamBinder(ast::NodeId), /* struct, impl or trait with ty params */ DefRegion(ast::NodeId), DefLabel(ast::NodeId), - DefMethod(ast::DefId /* method */, Option /* trait */, MethodProvenance), + DefMethod(ast::DefId /* method */, MethodProvenance), +} + +/// The result of resolving a path. +/// Before type checking completes, `depth` represents the number of +/// trailing segments which are yet unresolved. Afterwards, if there +/// were no errors, all paths should be fully resolved, with `depth` +/// set to `0` and `base_def` representing the final resolution. +/// +/// module::Type::AssocX::AssocY::MethodOrAssocType +/// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/// base_def depth = 3 +/// +/// ::AssocX::AssocY::MethodOrAssocType +/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ +/// base_def depth = 2 +#[derive(Copy, Debug)] +pub struct PathResolution { + pub base_def: Def, + pub last_private: LastPrivate, + pub depth: usize +} + +impl PathResolution { + /// Get the definition, if fully resolved, otherwise panic. + pub fn full_def(&self) -> Def { + if self.depth != 0 { + panic!("path not fully resolved: {:?}", self); + } + self.base_def + } + + /// Get the DefId, if fully resolved, otherwise panic. + pub fn def_id(&self) -> ast::DefId { + self.full_def().def_id() + } } // Definition mapping -pub type DefMap = RefCell>; +pub type DefMap = RefCell>; // This is the replacement export map. It maps a module to all of the exports // within. pub type ExportMap = NodeMap>; @@ -78,12 +105,6 @@ pub enum MethodProvenance { FromImpl(ast::DefId), } -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum TyParamProvenance { - FromSelf(ast::DefId), - FromParam(ast::DefId), -} - impl MethodProvenance { pub fn map(self, f: F) -> MethodProvenance where F: FnOnce(ast::DefId) -> ast::DefId, @@ -95,34 +116,6 @@ impl MethodProvenance { } } -impl TyParamProvenance { - pub fn def_id(&self) -> ast::DefId { - match *self { - TyParamProvenance::FromSelf(ref did) => did.clone(), - TyParamProvenance::FromParam(ref did) => did.clone(), - } - } -} - -#[derive(Clone, Copy, Eq, PartialEq)] -pub enum TraitItemKind { - NonstaticMethodTraitItemKind, - StaticMethodTraitItemKind, - TypeTraitItemKind, -} - -impl TraitItemKind { - pub fn from_explicit_self_category(explicit_self_category: - ExplicitSelfCategory) - -> TraitItemKind { - if explicit_self_category == StaticExplicitSelfCategory { - StaticMethodTraitItemKind - } else { - NonstaticMethodTraitItemKind - } - } -} - impl Def { pub fn local_node_id(&self) -> ast::NodeId { let def_id = self.def_id(); @@ -132,25 +125,21 @@ impl Def { pub fn def_id(&self) -> ast::DefId { match *self { - DefFn(id, _) | DefStaticMethod(id, _) | DefMod(id) | - DefForeignMod(id) | DefStatic(id, _) | - DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) | - DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefaultImpl(id) | - DefMethod(id, _, _) | DefConst(id) | - DefAssociatedPath(TyParamProvenance::FromSelf(id), _) | - DefAssociatedPath(TyParamProvenance::FromParam(id), _) => { + DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | + DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | + DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | + DefMethod(id, _) | DefConst(id) => { id } DefLocal(id) | DefSelfTy(id) | DefUpvar(id, _) | DefRegion(id) | - DefTyParamBinder(id) | DefLabel(id) => { local_def(id) } - DefPrimTy(_) => panic!() + DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy") } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index ba81b2f3899..9c85b7748ab 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -175,7 +175,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { ast::ExprInlineAsm(..) => { self.require_unsafe(expr.span, "use of inline assembly"); } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { if let def::DefStatic(_, true) = ty::resolve_expr(self.tcx, expr) { self.require_unsafe(expr.span, "use of mutable static"); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 625093e3c5d..a1e38a1c8bd 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -422,7 +422,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.walk_expr(&**subexpr) } - ast::ExprPath(_) | ast::ExprQPath(_) => { } + ast::ExprPath(..) => { } ast::ExprUnary(ast::UnDeref, ref base) => { // *base if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) { @@ -1017,7 +1017,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // Each match binding is effectively an assignment to the // binding being produced. - let def = def_map.borrow()[pat.id].clone(); + let def = def_map.borrow()[pat.id].full_def(); match mc.cat_def(pat.id, pat.span, pat_ty, def) { Ok(binding_cmt) => { delegate.mutate(pat.id, pat.span, binding_cmt, Init); @@ -1097,13 +1097,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { match pat.node { ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => { - match def_map.get(&pat.id) { + match def_map.get(&pat.id).map(|d| d.full_def()) { None => { // no definition found: pat is not a // struct or enum pattern. } - Some(&def::DefVariant(enum_did, variant_did, _is_struct)) => { + Some(def::DefVariant(enum_did, variant_did, _is_struct)) => { let downcast_cmt = if ty::enum_is_univariant(tcx, enum_did) { cmt_pat @@ -1119,7 +1119,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { delegate.matched_pat(pat, downcast_cmt, match_mode); } - Some(&def::DefStruct(..)) | Some(&def::DefTy(_, false)) => { + Some(def::DefStruct(..)) | Some(def::DefTy(_, false)) => { // A struct (in either the value or type // namespace; we encounter the former on // e.g. patterns for unit structs). @@ -1131,14 +1131,14 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { delegate.matched_pat(pat, cmt_pat, match_mode); } - Some(&def::DefConst(..)) | - Some(&def::DefLocal(..)) => { + Some(def::DefConst(..)) | + Some(def::DefLocal(..)) => { // This is a leaf (i.e. identifier binding // or constant value to match); thus no // `matched_pat` call. } - Some(def @ &def::DefTy(_, true)) => { + Some(def @ def::DefTy(_, true)) => { // An enum's type -- should never be in a // pattern. diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 110c7bf41e5..da4df813030 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1233,8 +1233,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } ty_queue.push(&*mut_ty.ty); } - ast::TyPath(ref path, id) => { - let a_def = match self.tcx.def_map.borrow().get(&id) { + ast::TyPath(ref maybe_qself, ref path) => { + let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) { None => { self.tcx .sess @@ -1242,7 +1242,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { "unbound path {}", pprust::path_to_string(path))) } - Some(&d) => d + Some(d) => d.full_def() }; match a_def { def::DefTy(did, _) | def::DefStruct(did) => { @@ -1277,9 +1277,16 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { region_names: region_names }; let new_path = self.rebuild_path(rebuild_info, lifetime); + let qself = maybe_qself.as_ref().map(|qself| { + ast::QSelf { + ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime, + anon_nums, region_names), + position: qself.position + } + }); let to = ast::Ty { id: cur_ty.id, - node: ast::TyPath(new_path, id), + node: ast::TyPath(qself, new_path), span: cur_ty.span }; new_ty = self.rebuild_ty(new_ty, P(to)); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 145fccd7972..2ac019aa964 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -445,8 +445,8 @@ fn visit_arm(ir: &mut IrMaps, arm: &ast::Arm) { fn visit_expr(ir: &mut IrMaps, expr: &Expr) { match expr.node { // live nodes required for uses or definitions of variables: - ast::ExprPath(_) | ast::ExprQPath(_) => { - let def = ir.tcx.def_map.borrow()[expr.id].clone(); + ast::ExprPath(..) => { + let def = ir.tcx.def_map.borrow()[expr.id].full_def(); debug!("expr {}: path that leads to {:?}", expr.id, def); if let DefLocal(..) = def { ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); @@ -705,8 +705,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { Some(_) => { // Refers to a labeled loop. Use the results of resolve // to find with one - match self.ir.tcx.def_map.borrow().get(&id) { - Some(&DefLabel(loop_id)) => loop_id, + match self.ir.tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { + Some(DefLabel(loop_id)) => loop_id, _ => self.ir.tcx.sess.span_bug(sp, "label on break/loop \ doesn't refer to a loop") } @@ -947,7 +947,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { // Interesting cases with control flow or which gen/kill - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { self.access_path(expr, succ, ACC_READ | ACC_USE) } @@ -1275,7 +1275,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // just ignore such cases and treat them as reads. match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => succ, + ast::ExprPath(..) => succ, ast::ExprField(ref e, _) => self.propagate_through_expr(&**e, succ), ast::ExprTupField(ref e, _) => self.propagate_through_expr(&**e, succ), _ => self.propagate_through_expr(expr, succ) @@ -1286,7 +1286,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint) -> LiveNode { match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { self.access_path(expr, succ, acc) } @@ -1300,7 +1300,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: uint) -> LiveNode { - match self.ir.tcx.def_map.borrow()[expr.id].clone() { + match self.ir.tcx.def_map.borrow()[expr.id].full_def() { DefLocal(nid) => { let ln = self.live_node(expr.id, expr.span); if acc != 0 { @@ -1468,7 +1468,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) | - ast::ExprRange(..) | ast::ExprQPath(..) => { + ast::ExprRange(..) => { visit::walk_expr(this, expr); } ast::ExprIfLet(..) => { @@ -1561,8 +1561,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_lvalue(&mut self, expr: &Expr) { match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { - if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].clone() { + ast::ExprPath(..) => { + if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].full_def() { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually // mutable, then check for a reassignment to flag the mutability diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5aa6be43002..c4446b87855 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -529,8 +529,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } - ast::ExprPath(_) | ast::ExprQPath(_) => { - let def = (*self.tcx().def_map.borrow())[expr.id]; + ast::ExprPath(..) => { + let def = self.tcx().def_map.borrow()[expr.id].full_def(); self.cat_def(expr.id, expr.span, expr_ty, def) } @@ -575,14 +575,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { match def { def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) | - def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => { + def::DefFn(..) | def::DefMethod(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | - def::DefaultImpl(_) | def::DefTy(..) | def::DefPrimTy(_) | - def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) | + def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | + def::DefTyParam(..) | def::DefRegion(_) | def::DefLabel(_) | def::DefSelfTy(..) | - def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> { + def::DefAssociatedTy(..) => { Ok(Rc::new(cmt_ { id:id, span:span, @@ -1199,14 +1199,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { (*op)(self, cmt.clone(), pat); - let def_map = self.tcx().def_map.borrow(); - let opt_def = def_map.get(&pat.id); + let opt_def = self.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def()); // Note: This goes up here (rather than within the PatEnum arm // alone) because struct patterns can refer to struct types or // to struct variants within enums. let cmt = match opt_def { - Some(&def::DefVariant(enum_did, variant_did, _)) + Some(def::DefVariant(enum_did, variant_did, _)) // univariant enums do not need downcasts if !ty::enum_is_univariant(self.tcx(), enum_did) => { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) @@ -1224,7 +1223,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } ast::PatEnum(_, Some(ref subpats)) => { match opt_def { - Some(&def::DefVariant(..)) => { + Some(def::DefVariant(..)) => { // variant(x, y, z) for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2) @@ -1237,7 +1236,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { try!(self.cat_pattern_(subcmt, &**subpat, op)); } } - Some(&def::DefStruct(..)) => { + Some(def::DefStruct(..)) => { for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2) let cmt_field = @@ -1247,7 +1246,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { try!(self.cat_pattern_(cmt_field, &**subpat, op)); } } - Some(&def::DefConst(..)) => { + Some(def::DefConst(..)) => { for subpat in subpats { try!(self.cat_pattern_(cmt.clone(), &**subpat, op)); } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index a7df2f4a5da..c5abff3b963 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -34,8 +34,8 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool { ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => { - match dm.borrow().get(&pat.id) { - Some(&DefVariant(..)) => true, + match dm.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefVariant(..)) => true, _ => false } } @@ -49,8 +49,8 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool { ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => { - match dm.borrow().get(&pat.id) { - Some(&DefVariant(..)) | Some(&DefStruct(..)) => true, + match dm.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefVariant(..)) | Some(DefStruct(..)) => true, _ => false } } @@ -61,8 +61,8 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool { pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatIdent(_, _, None) | ast::PatEnum(..) => { - match dm.borrow().get(&pat.id) { - Some(&DefConst(..)) => true, + match dm.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefConst(..)) => true, _ => false } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index dd1e32d13a2..3a253735f92 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -16,7 +16,7 @@ pub use self::PrivateDep::*; pub use self::ImportUse::*; pub use self::LastPrivate::*; -use util::nodemap::{DefIdSet, NodeMap, NodeSet}; +use util::nodemap::{DefIdSet, NodeSet}; use syntax::ast; @@ -32,9 +32,6 @@ pub type ExternalExports = DefIdSet; /// reexporting a public struct doesn't inline the doc). pub type PublicItems = NodeSet; -// FIXME: dox -pub type LastPrivateMap = NodeMap; - #[derive(Copy, Debug)] pub enum LastPrivate { LastMod(PrivateDep), diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 550f4e39447..45d565ec693 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -94,9 +94,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { fn visit_expr(&mut self, expr: &ast::Expr) { match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let def = match self.tcx.def_map.borrow().get(&expr.id) { - Some(&def) => def, + Some(d) => d.full_def(), None => { self.tcx.sess.span_bug(expr.span, "def ID not in def map?!") diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index bef98f5bd02..a8a2887644a 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -165,13 +165,13 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { visit::walk_ty(this, ty); }); } - ast::TyPath(ref path, id) => { + ast::TyPath(None, ref path) => { // if this path references a trait, then this will resolve to // a trait ref, which introduces a binding scope. - match self.def_map.borrow().get(&id) { - Some(&def::DefaultImpl(..)) => { + match self.def_map.borrow().get(&ty.id).map(|d| (d.base_def, d.depth)) { + Some((def::DefTrait(..), 0)) => { self.with(LateScope(&Vec::new(), self.scope), |_, this| { - this.visit_path(path, id); + this.visit_path(path, ty.id); }); } _ => { @@ -270,16 +270,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { for lifetime in &trait_ref.bound_lifetimes { this.visit_lifetime_def(lifetime); } - this.visit_trait_ref(&trait_ref.trait_ref) + visit::walk_path(this, &trait_ref.trait_ref.path) }) } else { self.visit_trait_ref(&trait_ref.trait_ref) } } - - fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) { - self.visit_path(&trait_ref.path, trait_ref.ref_id); - } } impl<'a> LifetimeContext<'a> { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index cfa5e5fce38..f67e470ee54 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -393,12 +393,14 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId, cb: &mut FnMut(ast::DefId, Span, &Option)) { - let did = match tcx.def_map.borrow().get(&id) { - Some(&def::DefPrimTy(..)) => return, - Some(def) => def.def_id(), - None => return - }; - maybe_do_stability_check(tcx, did, path.span, cb) + match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { + Some(def::DefPrimTy(..)) => {} + Some(def) => { + maybe_do_stability_check(tcx, def.def_id(), path.span, cb); + } + None => {} + } + } fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3d059e27c52..91313633397 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -709,7 +709,7 @@ pub struct ctxt<'tcx> { pub impl_trait_cache: RefCell>>>>, - pub trait_refs: RefCell>>>, + pub impl_trait_refs: RefCell>>>, pub trait_defs: RefCell>>>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its @@ -2423,7 +2423,7 @@ impl<'tcx> CommonTypes<'tcx> { pub fn mk_ctxt<'tcx>(s: Session, arenas: &'tcx CtxtArenas<'tcx>, - dm: DefMap, + def_map: DefMap, named_region_map: resolve_lifetime::NamedRegionMap, map: ast_map::Map<'tcx>, freevars: RefCell, @@ -2445,11 +2445,11 @@ pub fn mk_ctxt<'tcx>(s: Session, item_variance_map: RefCell::new(DefIdMap()), variance_computed: Cell::new(false), sess: s, - def_map: dm, + def_map: def_map, region_maps: region_maps, node_types: RefCell::new(FnvHashMap()), item_substs: RefCell::new(NodeMap()), - trait_refs: RefCell::new(NodeMap()), + impl_trait_refs: RefCell::new(NodeMap()), trait_defs: RefCell::new(DefIdMap()), predicates: RefCell::new(DefIdMap()), object_cast_map: RefCell::new(NodeMap()), @@ -4174,12 +4174,12 @@ pub fn named_element_ty<'tcx>(cx: &ctxt<'tcx>, } } -pub fn node_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) +pub fn impl_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Rc> { - match cx.trait_refs.borrow().get(&id) { + match cx.impl_trait_refs.borrow().get(&id) { Some(ty) => ty.clone(), None => cx.sess.bug( - &format!("node_id_to_trait_ref: no trait ref for node `{}`", + &format!("impl_id_to_trait_ref: no trait ref for impl `{}`", cx.map.node_to_string(id))) } } @@ -4502,7 +4502,7 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, pub fn resolve_expr(tcx: &ctxt, expr: &ast::Expr) -> def::Def { match tcx.def_map.borrow().get(&expr.id) { - Some(&def) => def, + Some(def) => def.full_def(), None => { tcx.sess.span_bug(expr.span, &format!( "no def-map entry for expr {}", expr.id)); @@ -4550,7 +4550,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { } match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { match resolve_expr(tcx, expr) { def::DefVariant(tid, vid, _) => { let variant_info = enum_variant_with_id(tcx, tid, vid); @@ -4581,7 +4581,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { def::DefFn(_, true) => RvalueDpsExpr, // Fn pointers are just scalar values. - def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => RvalueDatumExpr, + def::DefFn(..) | def::DefMethod(..) => RvalueDatumExpr, // Note: there is actually a good case to be made that // DefArg's, particularly those of immediate type, ought to @@ -4685,11 +4685,10 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprBox(Some(ref place), _) => { // Special case `Box` for now: - let definition = match tcx.def_map.borrow().get(&place.id) { - Some(&def) => def, + let def_id = match tcx.def_map.borrow().get(&place.id) { + Some(def) => def.def_id(), None => panic!("no def for place"), }; - let def_id = definition.def_id(); if tcx.lang_items.exchange_heap() == Some(def_id) { RvalueDatumExpr } else { @@ -5116,25 +5115,16 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) memoized(&cx.impl_trait_cache, id, |id: ast::DefId| { if id.krate == ast::LOCAL_CRATE { debug!("(impl_trait_ref) searching for trait impl {:?}", id); - match cx.map.find(id.node) { - Some(ast_map::NodeItem(item)) => { - match item.node { - ast::ItemImpl(_, _, _, ref opt_trait, _, _) => { - match opt_trait { - &Some(ref t) => { - let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id); - Some(trait_ref) - } - &None => None - } - } - ast::ItemDefaultImpl(_, ref ast_trait_ref) => { - Some(ty::node_id_to_trait_ref(cx, ast_trait_ref.ref_id)) - } - _ => None + if let Some(ast_map::NodeItem(item)) = cx.map.find(id.node) { + match item.node { + ast::ItemImpl(_, _, _, Some(_), _, _) | + ast::ItemDefaultImpl(..) => { + Some(ty::impl_id_to_trait_ref(cx, id.node)) } + _ => None } - _ => None + } else { + None } } else { csearch::get_impl_trait(cx, id) @@ -5143,10 +5133,7 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) } pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId { - let def = *tcx.def_map.borrow() - .get(&tr.ref_id) - .expect("no def-map entry for trait"); - def.def_id() + tcx.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() } pub fn try_add_builtin_trait( @@ -5848,7 +5835,7 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { } Err(_) => { let found = match count_expr.node { - ast::ExprPath(ast::Path { + ast::ExprPath(None, ast::Path { global: false, ref segments, .. diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 2fc43ab26b5..e16df61c25c 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -244,8 +244,7 @@ mod svh_visitor { SawExprAssignOp(ast::BinOp_), SawExprIndex, SawExprRange, - SawExprPath, - SawExprQPath, + SawExprPath(Option), SawExprAddrOf(ast::Mutability), SawExprRet, SawExprInlineAsm(&'a ast::InlineAsm), @@ -277,8 +276,7 @@ mod svh_visitor { ExprTupField(_, id) => SawExprTupField(id.node), ExprIndex(..) => SawExprIndex, ExprRange(..) => SawExprRange, - ExprPath(..) => SawExprPath, - ExprQPath(..) => SawExprQPath, + ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), ExprAddrOf(m, _) => SawExprAddrOf(m), ExprBreak(id) => SawExprBreak(id.map(content)), ExprAgain(id) => SawExprAgain(id.map(content)), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b12f05d7c50..bd911c20afc 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -571,7 +571,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, export_map, trait_map, external_exports, - last_private_map, glob_map, } = time(time_passes, "resolution", (), @@ -620,10 +619,9 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, time(time_passes, "const checking", (), |_| middle::check_const::check_crate(&ty_cx)); - let maps = (external_exports, last_private_map); let (exported_items, public_items) = - time(time_passes, "privacy checking", maps, |(a, b)| - rustc_privacy::check_crate(&ty_cx, &export_map, a, b)); + time(time_passes, "privacy checking", (), |_| + rustc_privacy::check_crate(&ty_cx, &export_map, external_exports)); // Do not move this check past lint time(time_passes, "stability index", (), |_| diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f0a640aa2e0..436a826687e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,7 +17,6 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(core)] #![feature(int_uint)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -38,8 +37,7 @@ use rustc::middle::def; use rustc::middle::privacy::ImportUse::*; use rustc::middle::privacy::LastPrivate::*; use rustc::middle::privacy::PrivateDep::*; -use rustc::middle::privacy::{ExportedItems, PublicItems, LastPrivateMap}; -use rustc::middle::privacy::{ExternalExports}; +use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems}; use rustc::middle::ty::{MethodTypeParam, MethodStatic}; use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam}; use rustc::middle::ty::{MethodStaticClosure, MethodObject}; @@ -259,8 +257,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // * Private trait impls for private types can be completely ignored ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => { let public_ty = match ty.node { - ast::TyPath(_, id) => { - match self.tcx.def_map.borrow()[id].clone() { + ast::TyPath(..) => { + match self.tcx.def_map.borrow()[ty.id].full_def() { def::DefPrimTy(..) => true, def => { let did = def.def_id(); @@ -326,8 +324,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } ast::ItemTy(ref ty, _) if public_first => { - if let ast::TyPath(_, id) = ty.node { - match self.tcx.def_map.borrow()[id].clone() { + if let ast::TyPath(..) = ty.node { + match self.tcx.def_map.borrow()[ty.id].full_def() { def::DefPrimTy(..) | def::DefTyParam(..) => {}, def => { let did = def.def_id(); @@ -379,7 +377,6 @@ struct PrivacyVisitor<'a, 'tcx: 'a> { in_foreign: bool, parents: NodeMap, external_exports: ExternalExports, - last_private_map: LastPrivateMap, } enum PrivacyResult { @@ -628,11 +625,11 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // back up the chains to find the relevant struct/enum that // was private. ast::ItemImpl(_, _, _, _, ref ty, _) => { - let id = match ty.node { - ast::TyPath(_, id) => id, + match ty.node { + ast::TyPath(..) => {} _ => return Some((err_span, err_msg, None)), }; - let def = self.tcx.def_map.borrow()[id].clone(); + let def = self.tcx.def_map.borrow()[ty.id].full_def(); let did = def.def_id(); assert!(is_local(did)); match self.tcx.map.get(did.node) { @@ -716,21 +713,21 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } // Checks that a path is in scope. - fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) { + fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Ident) { debug!("privacy - path {}", self.nodestr(path_id)); - let orig_def = self.tcx.def_map.borrow()[path_id].clone(); + let path_res = self.tcx.def_map.borrow()[path_id]; let ck = |tyname: &str| { let ck_public = |def: ast::DefId| { debug!("privacy - ck_public {:?}", def); - let name = token::get_ident(path.segments.last().unwrap().identifier); - let origdid = orig_def.def_id(); + let name = token::get_ident(last); + let origdid = path_res.def_id(); self.ensure_public(span, def, Some(origdid), &format!("{} `{}`", tyname, name)) }; - match self.last_private_map[path_id] { + match path_res.last_private { LastMod(AllPublic) => {}, LastMod(DependsOn(def)) => { self.report_error(ck_public(def)); @@ -794,17 +791,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // def map is not. Therefore the names we work out below will not always // be accurate and we can get slightly wonky error messages (but type // checking is always correct). - match self.tcx.def_map.borrow()[path_id].clone() { - def::DefStaticMethod(..) => ck("static method"), + match path_res.full_def() { def::DefFn(..) => ck("function"), def::DefStatic(..) => ck("static"), def::DefConst(..) => ck("const"), def::DefVariant(..) => ck("variant"), def::DefTy(_, false) => ck("type"), def::DefTy(_, true) => ck("enum"), - def::DefaultImpl(..) => ck("trait"), + def::DefTrait(..) => ck("trait"), def::DefStruct(..) => ck("struct"), - def::DefMethod(_, Some(..), _) => ck("trait method"), def::DefMethod(..) => ck("method"), def::DefMod(..) => ck("module"), _ => {} @@ -832,37 +827,22 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &ast::Item) { - match item.node { - ast::ItemUse(ref vpath) => { - match vpath.node { - ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {} - ast::ViewPathList(ref prefix, ref list) => { - for pid in list { - match pid.node { - ast::PathListIdent { id, name } => { - debug!("privacy - ident item {}", id); - let seg = ast::PathSegment { - identifier: name, - parameters: ast::PathParameters::none(), - }; - let segs = vec![seg]; - let path = ast::Path { - global: false, - span: pid.span, - segments: segs, - }; - self.check_path(pid.span, id, &path); - } - ast::PathListMod { id } => { - debug!("privacy - mod item {}", id); - self.check_path(pid.span, id, prefix); - } - } + if let ast::ItemUse(ref vpath) = item.node { + if let ast::ViewPathList(ref prefix, ref list) = vpath.node { + for pid in list { + match pid.node { + ast::PathListIdent { id, name } => { + debug!("privacy - ident item {}", id); + self.check_path(pid.span, id, name); + } + ast::PathListMod { id } => { + debug!("privacy - mod item {}", id); + let name = prefix.segments.last().unwrap().identifier; + self.check_path(pid.span, id, name); } } } } - _ => {} } let orig_curitem = replace(&mut self.curitem, item.id); visit::walk_item(self, item); @@ -908,7 +888,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } } ty::ty_enum(_, _) => { - match self.tcx.def_map.borrow()[expr.id].clone() { + match self.tcx.def_map.borrow()[expr.id].full_def() { def::DefVariant(_, variant_id, _) => { for field in fields { self.check_field(expr.span, variant_id, @@ -927,7 +907,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { struct type?!"), } } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let guard = |did: ast::DefId| { let fields = ty::lookup_struct_fields(self.tcx, did); let any_priv = fields.iter().any(|f| { @@ -941,8 +921,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { with private fields"); } }; - match self.tcx.def_map.borrow().get(&expr.id) { - Some(&def::DefStruct(did)) => { + match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) { + Some(def::DefStruct(did)) => { guard(if is_local(did) { local_def(self.tcx.map.get_parent(did.node)) } else { @@ -981,8 +961,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } } ty::ty_enum(_, _) => { - match self.tcx.def_map.borrow().get(&pattern.id) { - Some(&def::DefVariant(_, variant_id, _)) => { + match self.tcx.def_map.borrow().get(&pattern.id).map(|d| d.full_def()) { + Some(def::DefVariant(_, variant_id, _)) => { for field in fields { self.check_field(pattern.span, variant_id, NamedField(field.node.ident.name)); @@ -1033,7 +1013,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) { - self.check_path(path.span, id, path); + self.check_path(path.span, id, path.segments.last().unwrap().identifier); visit::walk_path(self, path); } } @@ -1233,7 +1213,7 @@ struct CheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> { impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { fn path_is_private_type(&self, path_id: ast::NodeId) -> bool { - let did = match self.tcx.def_map.borrow().get(&path_id).cloned() { + let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) { // `int` etc. (None doesn't seem to occur.) None | Some(def::DefPrimTy(..)) => return false, Some(def) => def.def_id() @@ -1273,8 +1253,8 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { - if let ast::TyPath(_, path_id) = ty.node { - if self.inner.path_is_private_type(path_id) { + if let ast::TyPath(..) = ty.node { + if self.inner.path_is_private_type(ty.id) { self.contains_private = true; // found what we're looking for so let's stop // working. @@ -1398,7 +1378,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // // Those in 2. are warned via walk_generics and this // call here. - self.visit_trait_ref(tr) + visit::walk_path(self, &tr.path); } } } else if trait_ref.is_none() && self_is_public_path { @@ -1479,9 +1459,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_ty(&mut self, t: &ast::Ty) { - if let ast::TyPath(ref p, path_id) = t.node { + if let ast::TyPath(_, ref p) = t.node { if !self.tcx.sess.features.borrow().visible_private_types && - self.path_is_private_type(path_id) { + self.path_is_private_type(t.id) { self.tcx.sess.span_err(p.span, "private type in exported type signature"); } @@ -1517,8 +1497,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { pub fn check_crate(tcx: &ty::ctxt, export_map: &def::ExportMap, - external_exports: ExternalExports, - last_private_map: LastPrivateMap) + external_exports: ExternalExports) -> (ExportedItems, PublicItems) { let krate = tcx.map.krate(); @@ -1536,7 +1515,6 @@ pub fn check_crate(tcx: &ty::ctxt, tcx: tcx, parents: visitor.parents, external_exports: external_exports, - last_private_map: last_private_map, }; visit::walk_crate(&mut visitor, krate); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 31f21a84f84..67e2b409c8e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -23,10 +23,8 @@ use Namespace::{TypeNS, ValueNS}; use NameBindings; use ParentLink::{self, ModuleParentLink, BlockParentLink}; use Resolver; -use RibKind::*; use Shadowable; use TypeNsDef; -use TypeParameters::HasTypeParameters; use self::DuplicateCheckingMode::*; use self::NamespaceError::*; @@ -34,7 +32,6 @@ use self::NamespaceError::*; use rustc::metadata::csearch; use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; use rustc::middle::def::*; -use rustc::middle::subst::FnSpace; use syntax::ast::{Block, Crate}; use syntax::ast::{DeclItem, DefId}; @@ -42,19 +39,16 @@ use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic}; use syntax::ast::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn}; use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse}; -use syntax::ast::{MethodImplItem, Name, NamedField, NodeId}; -use syntax::ast::{PathListIdent, PathListMod}; -use syntax::ast::{Public, SelfStatic}; +use syntax::ast::{Name, NamedField, NodeId}; +use syntax::ast::{PathListIdent, PathListMod, Public}; use syntax::ast::StmtDecl; use syntax::ast::StructVariantKind; use syntax::ast::TupleVariantKind; -use syntax::ast::TyObjectSum; -use syntax::ast::{TypeImplItem, UnnamedField}; +use syntax::ast::UnnamedField; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ast::{Visibility}; -use syntax::ast::TyPath; use syntax::ast; -use syntax::ast_util::{self, PostExpansionMethod, local_def}; +use syntax::ast_util::{self, local_def}; use syntax::attr::AttrMetaMethods; use syntax::parse::token::{self, special_idents}; use syntax::codemap::{Span, DUMMY_SP}; @@ -181,12 +175,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { Some(TypeNS) } ForbidDuplicateTypesAndModules => { - match child.def_for_namespace(TypeNS) { - None => {} - Some(_) if child.get_module_if_available() - .map(|m| m.kind.get()) == - Some(ImplModuleKind) => {} - Some(_) => duplicate_type = TypeError + if child.defined_in_namespace(TypeNS) { + duplicate_type = TypeError; } Some(TypeNS) } @@ -465,9 +455,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { name_bindings.define_type(DefTy(local_def(item.id), true), sp, modifiers); let parent_link = self.get_parent_link(parent, name); - // We want to make sure the module type is EnumModuleKind - // even if there's already an ImplModuleKind module defined, - // since that's how we prevent duplicate enum definitions name_bindings.set_module_kind(parent_link, Some(local_def(item.id)), EnumModuleKind, @@ -517,147 +504,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { parent.clone() } - ItemImpl(_, _, _, None, ref ty, ref impl_items) => { - // If this implements an anonymous trait, then add all the - // methods within to a new module, if the type was defined - // within this module. - - let mod_name = match ty.node { - TyPath(ref path, _) if path.segments.len() == 1 => { - // FIXME(18446) we should distinguish between the name of - // a trait and the name of an impl of that trait. - Some(path.segments.last().unwrap().identifier.name) - } - TyObjectSum(ref lhs_ty, _) => { - match lhs_ty.node { - TyPath(ref path, _) if path.segments.len() == 1 => { - Some(path.segments.last().unwrap().identifier.name) - } - _ => { - None - } - } - } - _ => { - None - } - }; - - let mod_name = match mod_name { - Some(mod_name) => mod_name, - None => { - self.resolve_error(ty.span, - "inherent implementations may \ - only be implemented in the same \ - module as the type they are \ - implemented for"); - return parent.clone(); - } - }; - // Create the module and add all methods. - let child_opt = parent.children.borrow().get(&mod_name) - .and_then(|m| m.get_module_if_available()); - let new_parent = match child_opt { - // It already exists - Some(ref child) if (child.kind.get() == ImplModuleKind || - child.kind.get() == TraitModuleKind) => { - child.clone() - } - Some(ref child) if child.kind.get() == EnumModuleKind || - child.kind.get() == TypeModuleKind => { - child.clone() - } - // Create the module - _ => { - let name_bindings = - self.add_child(mod_name, parent, ForbidDuplicateModules, sp); - - let parent_link = self.get_parent_link(parent, name); - let def_id = local_def(item.id); - let ns = TypeNS; - let is_public = - !name_bindings.defined_in_namespace(ns) || - name_bindings.defined_in_public_namespace(ns); - - name_bindings.define_module(parent_link, - Some(def_id), - ImplModuleKind, - false, - is_public, - sp); - - name_bindings.get_module() - } - }; - - // For each implementation item... - for impl_item in impl_items { - match *impl_item { - MethodImplItem(ref method) => { - // Add the method to the module. - let name = method.pe_ident().name; - let method_name_bindings = - self.add_child(name, - &new_parent, - ForbidDuplicateValues, - method.span); - let def = match method.pe_explicit_self() - .node { - SelfStatic => { - // Static methods become - // `DefStaticMethod`s. - DefStaticMethod(local_def(method.id), - FromImpl(local_def(item.id))) - } - _ => { - // Non-static methods become - // `DefMethod`s. - DefMethod(local_def(method.id), - None, - FromImpl(local_def(item.id))) - } - }; - - // NB: not IMPORTABLE - let modifiers = if method.pe_vis() == ast::Public { - PUBLIC - } else { - DefModifiers::empty() - }; - method_name_bindings.define_value( - def, - method.span, - modifiers); - } - TypeImplItem(ref typedef) => { - // Add the typedef to the module. - let name = typedef.ident.name; - let typedef_name_bindings = - self.add_child( - name, - &new_parent, - ForbidDuplicateTypesAndModules, - typedef.span); - let def = DefAssociatedTy(local_def( - typedef.id)); - // NB: not IMPORTABLE - let modifiers = if typedef.vis == ast::Public { - PUBLIC - } else { - DefModifiers::empty() - }; - typedef_name_bindings.define_type( - def, - typedef.span, - modifiers); - } - } - } - parent.clone() - } - ItemDefaultImpl(_, _) | - ItemImpl(_, _, _, Some(_), _, _) => parent.clone(), + ItemImpl(..) => parent.clone(), ItemTrait(_, _, _, ref items) => { let name_bindings = @@ -677,7 +525,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // Add the names of all the items to the trait info. for trait_item in items { - let (name, kind) = match *trait_item { + let (name, trait_item_id) = match *trait_item { ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { let ty_m = ast_util::trait_item_to_ty_method(trait_item); @@ -685,23 +533,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let name = ty_m.ident.name; // Add it as a name in the trait module. - let (def, static_flag) = match ty_m.explicit_self - .node { - SelfStatic => { - // Static methods become `DefStaticMethod`s. - (DefStaticMethod( - local_def(ty_m.id), - FromTrait(local_def(item.id))), - StaticMethodTraitItemKind) - } - _ => { - // Non-static methods become `DefMethod`s. - (DefMethod(local_def(ty_m.id), - Some(local_def(item.id)), - FromTrait(local_def(item.id))), - NonstaticMethodTraitItemKind) - } - }; + let def = DefMethod(local_def(ty_m.id), + FromTrait(local_def(item.id))); let method_name_bindings = self.add_child(name, @@ -713,11 +546,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ty_m.span, PUBLIC); - (name, static_flag) + (name, local_def(ty_m.id)) } ast::TypeTraitItem(ref associated_type) => { - let def = DefAssociatedTy(local_def( - associated_type.ty_param.id)); + let def = DefAssociatedTy(local_def(item.id), + local_def(associated_type.ty_param.id)); let name_bindings = self.add_child(associated_type.ty_param.ident.name, @@ -729,14 +562,15 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { associated_type.ty_param.span, PUBLIC); - (associated_type.ty_param.ident.name, TypeTraitItemKind) + (associated_type.ty_param.ident.name, + local_def(associated_type.ty_param.id)) } }; - self.trait_item_map.insert((name, def_id), kind); + self.trait_item_map.insert((name, def_id), trait_item_id); } - name_bindings.define_type(DefaultImpl(def_id), sp, modifiers); + name_bindings.define_type(DefTrait(def_id), sp, modifiers); parent.clone() } ItemMac(..) => parent.clone() @@ -773,12 +607,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, - foreign_item: &ForeignItem, - parent: &Rc, - f: F) where - F: FnOnce(&mut Resolver), - { + fn build_reduced_graph_for_foreign_item(&mut self, + foreign_item: &ForeignItem, + parent: &Rc) { let name = foreign_item.ident.name; let is_public = foreign_item.vis == ast::Public; let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; @@ -786,25 +617,15 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { self.add_child(name, parent, ForbidDuplicateValues, foreign_item.span); - match foreign_item.node { - ForeignItemFn(_, ref generics) => { - let def = DefFn(local_def(foreign_item.id), false); - name_bindings.define_value(def, foreign_item.span, modifiers); - - self.with_type_parameter_rib( - HasTypeParameters(generics, - FnSpace, - foreign_item.id, - NormalRibKind), - f); + let def = match foreign_item.node { + ForeignItemFn(..) => { + DefFn(local_def(foreign_item.id), false) } ForeignItemStatic(_, m) => { - let def = DefStatic(local_def(foreign_item.id), m); - name_bindings.define_value(def, foreign_item.span, modifiers); - - f(self.resolver) + DefStatic(local_def(foreign_item.id), m) } - } + }; + name_bindings.define_value(def, foreign_item.span, modifiers); } fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &Rc) -> Rc { @@ -850,8 +671,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let kind = match def { DefTy(_, true) => EnumModuleKind, - DefTy(_, false) => TypeModuleKind, - DefStruct(..) => ImplModuleKind, + DefTy(_, false) | DefStruct(..) => TypeModuleKind, _ => NormalModuleKind }; @@ -905,7 +725,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id) .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers); } - DefFn(..) | DefStaticMethod(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => { + DefFn(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => { debug!("(building reduced graph for external \ crate) building value (fn/static) {}", final_ident); // impl methods have already been defined with the correct importability modifier @@ -918,7 +738,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } child_name_bindings.define_value(def, DUMMY_SP, modifiers); } - DefaultImpl(def_id) => { + DefTrait(def_id) => { debug!("(building reduced graph for external \ crate) building type {}", final_ident); @@ -927,21 +747,19 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let trait_item_def_ids = csearch::get_trait_item_def_ids(&self.session.cstore, def_id); - for trait_item_def_id in &trait_item_def_ids { - let (trait_item_name, trait_item_kind) = - csearch::get_trait_item_name_and_kind( - &self.session.cstore, - trait_item_def_id.def_id()); + for trait_item_def in &trait_item_def_ids { + let trait_item_name = csearch::get_trait_name(&self.session.cstore, + trait_item_def.def_id()); debug!("(building reduced graph for external crate) ... \ adding trait item '{}'", token::get_name(trait_item_name)); - self.trait_item_map.insert((trait_item_name, def_id), trait_item_kind); + self.trait_item_map.insert((trait_item_name, def_id), + trait_item_def.def_id()); if is_exported { - self.external_exports - .insert(trait_item_def_id.def_id()); + self.external_exports.insert(trait_item_def.def_id()); } } @@ -956,7 +774,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { is_public, DUMMY_SP) } - DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => { + DefTy(..) | DefAssociatedTy(..) => { debug!("(building reduced graph for external \ crate) building type {}", final_ident); @@ -980,7 +798,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } DefLocal(..) | DefPrimTy(..) | DefTyParam(..) | DefUse(..) | DefUpvar(..) | DefRegion(..) | - DefTyParamBinder(..) | DefLabel(..) | DefSelfTy(..) => { + DefLabel(..) | DefSelfTy(..) => { panic!("didn't expect `{:?}`", def); } } @@ -1027,92 +845,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } } } - DlImpl(def) => { - match csearch::get_type_name_if_impl(&self.session.cstore, def) { - None => {} - Some(final_name) => { - let methods_opt = - csearch::get_methods_if_impl(&self.session.cstore, def); - match methods_opt { - Some(ref methods) if - methods.len() >= 1 => { - debug!("(building reduced graph for \ - external crate) processing \ - static methods for type name {}", - token::get_name(final_name)); - - let child_name_bindings = - self.add_child( - final_name, - root, - OverwriteDuplicates, - DUMMY_SP); - - // Process the static methods. First, - // create the module. - let type_module; - let type_def = child_name_bindings.type_def.borrow().clone(); - match type_def { - Some(TypeNsDef { - module_def: Some(module_def), - .. - }) => { - // We already have a module. This - // is OK. - type_module = module_def; - - // Mark it as an impl module if - // necessary. - type_module.kind.set(ImplModuleKind); - } - Some(_) | None => { - let parent_link = - self.get_parent_link(root, final_name); - child_name_bindings.define_module( - parent_link, - Some(def), - ImplModuleKind, - true, - true, - DUMMY_SP); - type_module = - child_name_bindings. - get_module(); - } - } - - // Add each static method to the module. - let new_parent = type_module; - for method_info in methods { - let name = method_info.name; - debug!("(building reduced graph for \ - external crate) creating \ - static method '{}'", - token::get_name(name)); - - let method_name_bindings = - self.add_child(name, - &new_parent, - OverwriteDuplicates, - DUMMY_SP); - let def = DefFn(method_info.def_id, false); - - // NB: not IMPORTABLE - let modifiers = if method_info.vis == ast::Public { - PUBLIC - } else { - DefModifiers::empty() - }; - method_name_bindings.define_value( - def, DUMMY_SP, modifiers); - } - } - - // Otherwise, do nothing. - Some(_) | None => {} - } - } - } + DlImpl(_) => { + debug!("(building reduced graph for external crate) \ + ignoring impl"); } DlField => { debug!("(building reduced graph for external crate) \ @@ -1241,16 +976,7 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { - let parent = &self.parent; - self.builder.build_reduced_graph_for_foreign_item(foreign_item, - parent, - |r| { - let mut v = BuildReducedGraphVisitor { - builder: GraphBuilder { resolver: r }, - parent: parent.clone() - }; - visit::walk_foreign_item(&mut v, foreign_item); - }) + self.builder.build_reduced_graph_for_foreign_item(foreign_item, &self.parent); } fn visit_block(&mut self, block: &Block) { diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index a239c73c110..aebbe144073 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -68,17 +68,17 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { "unused import".to_string()); } - let (v_priv, t_priv) = match self.last_private.get(&id) { - Some(&LastImport { - value_priv: v, - value_used: _, - type_priv: t, - type_used: _ - }) => (v, t), - Some(_) => { + let mut def_map = self.def_map.borrow_mut(); + let path_res = if let Some(r) = def_map.get_mut(&id) { + r + } else { + return; + }; + let (v_priv, t_priv) = match path_res.last_private { + LastImport { value_priv, type_priv, .. } => (value_priv, type_priv), + _ => { panic!("we should only have LastImport for `use` directives") } - _ => return, }; let mut v_used = if self.used_imports.contains(&(id, ValueNS)) { @@ -100,10 +100,12 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { _ => {}, } - self.last_private.insert(id, LastImport{value_priv: v_priv, - value_used: v_used, - type_priv: t_priv, - type_used: t_used}); + path_res.last_private = LastImport { + value_priv: v_priv, + value_used: v_used, + type_priv: t_priv, + type_used: t_used + }; } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c38b8fc7502..95523be68c3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -41,14 +41,12 @@ use self::ResolveResult::*; use self::FallbackSuggestion::*; use self::TypeParameters::*; use self::RibKind::*; -use self::MethodSort::*; use self::UseLexicalScopeFlag::*; use self::ModulePrefixResult::*; use self::NameSearchType::*; use self::BareIdentifierPatternResolution::*; use self::ParentLink::*; use self::ModuleKind::*; -use self::TraitReferenceType::*; use self::FallbackChecks::*; use rustc::session::Session; @@ -66,21 +64,18 @@ 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, ExprLoop, ExprWhile, ExprMethodCall}; -use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl}; +use syntax::ast::{ExprLoop, ExprWhile, ExprMethodCall}; +use syntax::ast::{ExprPath, ExprStruct, FnDecl}; use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics}; use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate}; use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse}; -use syntax::ast::{Local, MethodImplItem, Mod, Name, NodeId}; +use syntax::ast::{Local, MethodImplItem, Name, NodeId}; use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; -use syntax::ast::{PatRange, PatStruct, Path}; -use syntax::ast::{PolyTraitRef, PrimTy, SelfExplicit}; -use syntax::ast::{RegionTyParamBound, StructField}; -use syntax::ast::{TraitRef, TraitTyParamBound}; -use syntax::ast::{Ty, TyBool, TyChar, TyF32}; -use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt, TyObjectSum}; -use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyQPath}; +use syntax::ast::{PatRange, PatStruct, Path, PrimTy}; +use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32}; +use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt}; +use syntax::ast::{TyPath, TyPtr}; use syntax::ast::{TyRptr, TyStr, TyUs, TyU8, TyU16, TyU32, TyU64, TyUint}; use syntax::ast::{TypeImplItem}; use syntax::ast; @@ -89,8 +84,7 @@ use syntax::ast_util::{PostExpansionMethod, local_def, walk_pat}; use syntax::attr::AttrMetaMethods; use syntax::ext::mtwt; use syntax::parse::token::{self, special_names, special_idents}; -use syntax::codemap::{Span, Pos}; -use syntax::owned_slice::OwnedSlice; +use syntax::codemap::{self, Span, Pos}; use syntax::visit::{self, Visitor}; use std::collections::{HashMap, HashSet}; @@ -188,6 +182,72 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { fn visit_ty(&mut self, ty: &Ty) { self.resolve_type(ty); } + fn visit_generics(&mut self, generics: &Generics) { + self.resolve_generics(generics); + } + fn visit_poly_trait_ref(&mut self, + tref: &ast::PolyTraitRef, + m: &ast::TraitBoundModifier) { + match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) { + Ok(def) => self.record_def(tref.trait_ref.ref_id, def), + Err(_) => { /* error already reported */ } + } + visit::walk_poly_trait_ref(self, tref, m); + } + fn visit_variant(&mut self, variant: &ast::Variant, generics: &Generics) { + if let Some(ref dis_expr) = variant.node.disr_expr { + // resolve the discriminator expr as a constant + self.with_constant_rib(|this| { + this.visit_expr(&**dis_expr); + }); + } + + // `visit::walk_variant` without the discriminant expression. + match variant.node.kind { + ast::TupleVariantKind(ref variant_arguments) => { + for variant_argument in variant_arguments.iter() { + self.visit_ty(&*variant_argument.ty); + } + } + ast::StructVariantKind(ref struct_definition) => { + self.visit_struct_def(&**struct_definition, + variant.node.name, + generics, + variant.node.id); + } + } + } + fn visit_foreign_item(&mut self, foreign_item: &ast::ForeignItem) { + let type_parameters = match foreign_item.node { + ForeignItemFn(_, ref generics) => { + HasTypeParameters(generics, FnSpace, ItemRibKind) + } + ForeignItemStatic(..) => NoTypeParameters + }; + self.with_type_parameter_rib(type_parameters, |this| { + visit::walk_foreign_item(this, foreign_item); + }); + } + fn visit_fn(&mut self, + function_kind: visit::FnKind<'v>, + declaration: &'v FnDecl, + block: &'v Block, + _: Span, + node_id: NodeId) { + let rib_kind = match function_kind { + visit::FkItemFn(_, generics, _, _) => { + self.visit_generics(generics); + ItemRibKind + } + visit::FkMethod(_, generics, method) => { + self.visit_generics(generics); + self.visit_explicit_self(method.pe_explicit_self()); + MethodRibKind + } + visit::FkFnBlock(..) => ClosureRibKind(node_id) + }; + self.resolve_function(rib_kind, declaration, block); + } } /// Contains data for specific types of import directives. @@ -231,9 +291,6 @@ enum TypeParameters<'a> { // were declared on (type, fn, etc) ParamSpace, - // ID of the enclosing item. - NodeId, - // The kind of the rib used for type parameters. RibKind) } @@ -253,8 +310,7 @@ enum RibKind { // methods. Allow references to ty params that impl or trait // binds. Disallow any other upvars (including other ty params that are // upvars). - // parent; method itself - MethodRibKind(NodeId, MethodSort), + MethodRibKind, // We passed through an item scope. Disallow upvars. ItemRibKind, @@ -263,13 +319,6 @@ enum RibKind { ConstantItemRibKind } -// Methods can be required or provided. RequiredMethod methods only occur in traits. -#[derive(Copy, Debug)] -enum MethodSort { - RequiredMethod, - ProvidedMethod(NodeId) -} - #[derive(Copy)] enum UseLexicalScopeFlag { DontUseLexicalScope, @@ -465,7 +514,6 @@ enum ParentLink { enum ModuleKind { NormalModuleKind, TraitModuleKind, - ImplModuleKind, EnumModuleKind, TypeModuleKind, AnonymousModuleKind, @@ -586,16 +634,6 @@ struct NameBindings { value_def: RefCell>, //< Meaning in value namespace. } -/// Ways in which a trait can be referenced -#[derive(Copy)] -enum TraitReferenceType { - TraitImplementation, // impl SomeTrait for T { ... } - TraitDerivation, // trait T : SomeTrait { ... } - TraitBoundingTypeParameter, // fn f() { ... } - TraitObject, // Box SomeTrait> - TraitQPath, // :: -} - impl NameBindings { fn new() -> NameBindings { NameBindings { @@ -861,7 +899,7 @@ struct Resolver<'a, 'tcx:'a> { graph_root: NameBindings, - trait_item_map: FnvHashMap<(Name, DefId), TraitItemKind>, + trait_item_map: FnvHashMap<(Name, DefId), DefId>, structs: FnvHashMap>, @@ -901,7 +939,6 @@ struct Resolver<'a, 'tcx:'a> { export_map: ExportMap, trait_map: TraitMap, external_exports: ExternalExports, - last_private: LastPrivateMap, // Whether or not to print error messages. Can be set to true // when getting additional info for error message suggestions, @@ -976,7 +1013,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { used_imports: HashSet::new(), used_crates: HashSet::new(), external_exports: DefIdSet(), - last_private: NodeMap(), emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, @@ -1096,8 +1132,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { result } - fn path_names_to_string(&self, path: &Path) -> String { - let names: Vec = path.segments + fn path_names_to_string(&self, path: &Path, depth: usize) -> String { + let names: Vec = path.segments[..path.segments.len()-depth] .iter() .map(|seg| seg.identifier.name) .collect(); @@ -1534,31 +1570,36 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - let value_private = match import_resolution.value_target { - Some(ref target) => { - let def = target.bindings.def_for_namespace(ValueNS).unwrap(); - self.def_map.borrow_mut().insert(directive.id, def); - let did = def.def_id(); - if value_used_public {Some(lp)} else {Some(DependsOn(did))} - }, - // AllPublic here and below is a dummy value, it should never be used because - // _exists is false. - None => None, - }; - let type_private = match import_resolution.type_target { - Some(ref target) => { - let def = target.bindings.def_for_namespace(TypeNS).unwrap(); - self.def_map.borrow_mut().insert(directive.id, def); - let did = def.def_id(); - if type_used_public {Some(lp)} else {Some(DependsOn(did))} - }, - None => None, + let value_def_and_priv = import_resolution.value_target.as_ref().map(|target| { + let def = target.bindings.def_for_namespace(ValueNS).unwrap(); + (def, if value_used_public { lp } else { DependsOn(def.def_id()) }) + }); + let type_def_and_priv = import_resolution.type_target.as_ref().map(|target| { + let def = target.bindings.def_for_namespace(TypeNS).unwrap(); + (def, if type_used_public { lp } else { DependsOn(def.def_id()) }) + }); + + let import_lp = LastImport { + value_priv: value_def_and_priv.map(|(_, p)| p), + value_used: Used, + type_priv: type_def_and_priv.map(|(_, p)| p), + type_used: Used }; - self.last_private.insert(directive.id, LastImport{value_priv: value_private, - value_used: Used, - type_priv: type_private, - type_used: Used}); + if let Some((def, _)) = value_def_and_priv { + self.def_map.borrow_mut().insert(directive.id, PathResolution { + base_def: def, + last_private: import_lp, + depth: 0 + }); + } + if let Some((def, _)) = type_def_and_priv { + self.def_map.borrow_mut().insert(directive.id, PathResolution { + base_def: def, + last_private: import_lp, + depth: 0 + }); + } debug!("(resolving single import) successfully resolved import"); return Success(()); @@ -1676,12 +1717,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Record the destination of this import - match containing_module.def_id.get() { - Some(did) => { - self.def_map.borrow_mut().insert(id, DefMod(did)); - self.last_private.insert(id, lp); - } - None => {} + if let Some(did) = containing_module.def_id.get() { + self.def_map.borrow_mut().insert(id, PathResolution { + base_def: DefMod(did), + last_private: lp, + depth: 0 + }); } debug!("(resolving glob import) successfully resolved import"); @@ -1822,13 +1863,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match import_resolution.value_target { Some(ref target) if target.shadowable != Shadowable::Always => { if let Some(ref value) = *name_bindings.value_def.borrow() { - let msg = format!("import `{}` conflicts with value \ - in this module", - &token::get_name(name)); - span_err!(self.session, import_span, E0255, "{}", &msg[..]); + span_err!(self.session, import_span, E0255, + "import `{}` conflicts with value in this module", + &token::get_name(name)); if let Some(span) = value.value_span { - self.session.span_note(span, - "conflicting value here"); + self.session.span_note(span, "conflicting value here"); } } } @@ -1838,41 +1877,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match import_resolution.type_target { Some(ref target) if target.shadowable != Shadowable::Always => { if let Some(ref ty) = *name_bindings.type_def.borrow() { - match ty.module_def { - None => { - let msg = format!("import `{}` conflicts with type in \ - this module", - &token::get_name(name)); - span_err!(self.session, import_span, E0256, "{}", &msg[..]); - if let Some(span) = ty.type_span { - self.session.span_note(span, - "note conflicting type here") - } - } - Some(ref module_def) => { - match module_def.kind.get() { - ImplModuleKind => { - if let Some(span) = ty.type_span { - let msg = format!("inherent implementations \ - are only allowed on types \ - defined in the current module"); - span_err!(self.session, span, E0257, "{}", &msg[..]); - self.session.span_note(import_span, - "import from other module here") - } - } - _ => { - let msg = format!("import `{}` conflicts with existing \ - submodule", - &token::get_name(name)); - span_err!(self.session, import_span, E0258, "{}", &msg[..]); - if let Some(span) = ty.type_span { - self.session.span_note(span, - "note conflicting module here") - } - } - } - } + let (what, note) = if ty.module_def.is_some() { + ("existing submodule", "note conflicting module here") + } else { + ("type in this module", "note conflicting type here") + }; + span_err!(self.session, import_span, E0256, + "import `{}` conflicts with {}", + &token::get_name(name), what); + if let Some(span) = ty.type_span { + self.session.span_note(span, note); } } } @@ -2226,7 +2240,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return Failed(None); } TraitModuleKind | - ImplModuleKind | EnumModuleKind | TypeModuleKind | AnonymousModuleKind => { @@ -2324,7 +2337,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match new_module.kind.get() { NormalModuleKind => return Some(new_module), TraitModuleKind | - ImplModuleKind | EnumModuleKind | TypeModuleKind | AnonymousModuleKind => module_ = new_module, @@ -2341,7 +2353,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match module_.kind.get() { NormalModuleKind => return module_, TraitModuleKind | - ImplModuleKind | EnumModuleKind | TypeModuleKind | AnonymousModuleKind => { @@ -2600,14 +2611,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { def_like: DefLike, span: Span) -> Option { - match def_like { - DlDef(d @ DefUpvar(..)) => { + let mut def = match def_like { + DlDef(def) => def, + _ => return Some(def_like) + }; + match def { + DefUpvar(..) => { self.session.span_bug(span, - &format!("unexpected {:?} in bindings", d)) + &format!("unexpected {:?} in bindings", def)) } - DlDef(d @ DefLocal(_)) => { - let node_id = d.def_id().node; - let mut def = d; + DefLocal(node_id) => { for rib in ribs { match rib.kind { NormalRibKind => { @@ -2631,39 +2644,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }.push(Freevar { def: prev_def, span: span }); seen.insert(node_id); } - MethodRibKind(item_id, _) => { - // If the def is a ty param, and came from the parent - // item, it's ok - match def { - DefTyParam(_, _, did, _) if { - self.def_map.borrow().get(&did.node).cloned() - == Some(DefTyParamBinder(item_id)) - } => {} // ok - DefSelfTy(did) if did == item_id => {} // ok - _ => { - // This was an attempt to access an upvar inside a - // named function item. This is not allowed, so we - // report an error. - - self.resolve_error( - span, - "can't capture dynamic environment in a fn item; \ - use the || { ... } closure form instead"); - - return None; - } - } - } - ItemRibKind => { + ItemRibKind | MethodRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. - self.resolve_error( - span, + self.resolve_error(span, "can't capture dynamic environment in a fn item; \ - use the || { ... } closure form instead"); - + use the || { ... } closure form instead"); return None; } ConstantItemRibKind => { @@ -2671,42 +2659,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.resolve_error(span, "attempt to use a non-constant \ value in a constant"); - + return None; } } } - Some(DlDef(def)) } - DlDef(def @ DefTyParam(..)) | - DlDef(def @ DefSelfTy(..)) => { + DefTyParam(..) | DefSelfTy(_) => { for rib in ribs { match rib.kind { - NormalRibKind | ClosureRibKind(..) => { + NormalRibKind | MethodRibKind | ClosureRibKind(..) => { // Nothing to do. Continue. } - MethodRibKind(item_id, _) => { - // If the def is a ty param, and came from the parent - // item, it's ok - match def { - DefTyParam(_, _, did, _) if { - self.def_map.borrow().get(&did.node).cloned() - == Some(DefTyParamBinder(item_id)) - } => {} // ok - DefSelfTy(did) if did == item_id => {} // ok - - _ => { - // This was an attempt to use a type parameter outside - // its scope. - - self.resolve_error(span, - "can't use type parameters from \ - outer function; try using a local \ - type parameter instead"); - - return None; - } - } - } ItemRibKind => { // This was an attempt to use a type parameter outside // its scope. @@ -2715,7 +2678,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "can't use type parameters from \ outer function; try using a local \ type parameter instead"); - return None; } ConstantItemRibKind => { @@ -2723,14 +2685,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.resolve_error(span, "cannot use an outer type \ parameter in this context"); - + return None; } } } - Some(DlDef(def)) } - _ => Some(def_like) + _ => {} } + Some(DlDef(def)) } /// Searches the current set of local scopes and @@ -2743,13 +2705,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // FIXME #4950: Try caching? for (i, rib) in ribs.iter().enumerate().rev() { - match rib.bindings.get(&name).cloned() { - Some(def_like) => { - return self.upvarify(&ribs[i + 1..], def_like, span); - } - None => { - // Continue. - } + if let Some(def_like) = rib.bindings.get(&name).cloned() { + return self.upvarify(&ribs[i + 1..], def_like, span); } } @@ -2797,59 +2754,32 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { token::get_name(name)); match item.node { - - // enum item: resolve all the variants' discrs, - // then resolve the ty params - ItemEnum(ref enum_def, ref generics) => { + ItemEnum(_, ref generics) | + ItemTy(_, ref generics) | + ItemStruct(_, ref generics) => { self.check_if_primitive_type_name(name, item.span); - for variant in &(*enum_def).variants { - if let Some(ref dis_expr) = variant.node.disr_expr { - // resolve the discriminator expr - // as a constant - self.with_constant_rib(|this| { - this.resolve_expr(&**dis_expr); - }); - } - } - - // n.b. the discr expr gets visited twice. - // but maybe it's okay since the first time will signal an - // error if there is one? -- tjc self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, - item.id, ItemRibKind), - |this| { - this.resolve_type_parameters(&generics.ty_params); - this.resolve_where_clause(&generics.where_clause); - visit::walk_item(this, item); - }); + |this| visit::walk_item(this, item)); } - - ItemTy(_, ref generics) => { - self.check_if_primitive_type_name(name, item.span); - + ItemFn(_, _, _, ref generics, _) => { self.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - item.id, + FnSpace, ItemRibKind), - |this| { - this.resolve_type_parameters(&generics.ty_params); - visit::walk_item(this, item); - }); + |this| visit::walk_item(this, item)); } ItemDefaultImpl(_, ref trait_ref) => { - self.resolve_trait_reference(item.id, trait_ref, TraitImplementation); + self.with_optional_trait_ref(Some(trait_ref), |_| {}); } ItemImpl(_, _, ref generics, ref implemented_traits, ref self_type, ref impl_items) => { - self.resolve_implementation(item.id, - generics, + self.resolve_implementation(generics, implemented_traits, &**self_type, &impl_items[..]); @@ -2869,14 +2799,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Create a new rib for the trait-wide type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, - item.id, NormalRibKind), |this| { - this.resolve_type_parameters(&generics.ty_params); - this.resolve_where_clause(&generics.where_clause); - - this.resolve_type_parameter_bounds(item.id, bounds, - TraitDerivation); + this.visit_generics(generics); + visit::walk_ty_param_bounds_helper(this, bounds); for trait_item in &(*trait_items) { // Create a new rib for the trait_item-specific type @@ -2884,101 +2810,39 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // // FIXME #4951: Do we need a node ID here? - match *trait_item { - ast::RequiredMethod(ref ty_m) => { - this.with_type_parameter_rib - (HasTypeParameters(&ty_m.generics, - FnSpace, - item.id, - MethodRibKind(item.id, RequiredMethod)), - |this| { - - // Resolve the method-specific type - // parameters. - this.resolve_type_parameters( - &ty_m.generics.ty_params); - this.resolve_where_clause(&ty_m.generics - .where_clause); - - for argument in &ty_m.decl.inputs { - this.resolve_type(&*argument.ty); - } - - if let SelfExplicit(ref typ, _) = ty_m.explicit_self.node { - this.resolve_type(&**typ) - } - - if let ast::Return(ref ret_ty) = ty_m.decl.output { - this.resolve_type(&**ret_ty); - } - }); - } - ast::ProvidedMethod(ref m) => { - this.resolve_method(MethodRibKind(item.id, - ProvidedMethod(m.id)), - &**m) - } - ast::TypeTraitItem(ref data) => { - this.resolve_type_parameter(&data.ty_param); - visit::walk_trait_item(this, trait_item); - } - } + let type_parameters = match *trait_item { + ast::RequiredMethod(ref ty_m) => { + HasTypeParameters(&ty_m.generics, + FnSpace, + MethodRibKind) + } + ast::ProvidedMethod(ref m) => { + HasTypeParameters(m.pe_generics(), + FnSpace, + MethodRibKind) + } + ast::TypeTraitItem(ref assoc_ty) => { + let ty_param = &assoc_ty.ty_param; + this.check_if_primitive_type_name(ty_param.ident.name, + ty_param.span); + NoTypeParameters + } + }; + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_trait_item(this, trait_item) + }); } }); self.type_ribs.pop(); } - ItemStruct(ref struct_def, ref generics) => { - self.check_if_primitive_type_name(name, item.span); - - self.resolve_struct(item.id, - generics, - &struct_def.fields); - } - - ItemMod(ref module_) => { + ItemMod(_) | ItemForeignMod(_) => { self.with_scope(Some(name), |this| { - this.resolve_module(module_, item.span, name, - item.id); + visit::walk_item(this, item); }); } - ItemForeignMod(ref foreign_module) => { - self.with_scope(Some(name), |this| { - for foreign_item in &foreign_module.items { - match foreign_item.node { - ForeignItemFn(_, ref generics) => { - this.with_type_parameter_rib( - HasTypeParameters( - generics, FnSpace, foreign_item.id, - ItemRibKind), - |this| { - this.resolve_type_parameters(&generics.ty_params); - this.resolve_where_clause(&generics.where_clause); - visit::walk_foreign_item(this, &**foreign_item) - }); - } - ForeignItemStatic(..) => { - visit::walk_foreign_item(this, - &**foreign_item); - } - } - } - }); - } - - ItemFn(ref fn_decl, _, _, ref generics, ref block) => { - self.resolve_function(ItemRibKind, - Some(&**fn_decl), - HasTypeParameters - (generics, - FnSpace, - item.id, - ItemRibKind), - &**block); - } - ItemConst(..) | ItemStatic(..) => { self.with_constant_rib(|this| { visit::walk_item(this, item); @@ -2988,8 +2852,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ItemUse(ref view_path) => { // check for imports shadowing primitive types if let ast::ViewPathSimple(ident, _) = view_path.node { - match self.def_map.borrow().get(&item.id) { - Some(&DefTy(..)) | Some(&DefStruct(..)) | Some(&DefaultImpl(..)) | None => { + match self.def_map.borrow().get(&item.id).map(|d| d.full_def()) { + Some(DefTy(..)) | Some(DefStruct(..)) | Some(DefTrait(..)) | None => { self.check_if_primitive_type_name(ident.name, item.span); } _ => {} @@ -3007,35 +2871,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { F: FnOnce(&mut Resolver), { match type_parameters { - HasTypeParameters(generics, space, node_id, rib_kind) => { + HasTypeParameters(generics, space, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); let mut seen_bindings = HashSet::new(); for (index, type_parameter) in generics.ty_params.iter().enumerate() { let name = type_parameter.ident.name; - debug!("with_type_parameter_rib: {} {}", node_id, - type_parameter.id); + debug!("with_type_parameter_rib: {}", type_parameter.id); if seen_bindings.contains(&name) { self.resolve_error(type_parameter.span, &format!("the name `{}` is already \ - used for a type \ - parameter in this type \ - parameter list", - token::get_name( - name))) + used for a type \ + parameter in this type \ + parameter list", + token::get_name(name))) } seen_bindings.insert(name); - let def_like = DlDef(DefTyParam(space, - index as u32, - local_def(type_parameter.id), - name)); - // Associate this type parameter with - // the item that bound it - self.record_def(type_parameter.id, - (DefTyParamBinder(node_id), LastMod(AllPublic))); // plain insert (no renaming) - function_type_rib.bindings.insert(name, def_like); + function_type_rib.bindings.insert(name, + DlDef(DefTyParam(space, + index as u32, + local_def(type_parameter.id), + name))); } self.type_ribs.push(function_type_rib); } @@ -3073,224 +2931,84 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_function(&mut self, rib_kind: RibKind, - optional_declaration: Option<&FnDecl>, - type_parameters: TypeParameters, + declaration: &FnDecl, block: &Block) { // Create a value rib for the function. - let function_value_rib = Rib::new(rib_kind); - self.value_ribs.push(function_value_rib); + self.value_ribs.push(Rib::new(rib_kind)); // Create a label rib for the function. - let function_label_rib = Rib::new(rib_kind); - self.label_ribs.push(function_label_rib); + self.label_ribs.push(Rib::new(rib_kind)); - // If this function has type parameters, add them now. - self.with_type_parameter_rib(type_parameters, |this| { - // Resolve the type parameters. - match type_parameters { - NoTypeParameters => { - // Continue. - } - HasTypeParameters(ref generics, _, _, _) => { - this.resolve_type_parameters(&generics.ty_params); - this.resolve_where_clause(&generics.where_clause); - } - } + // Add each argument to the rib. + let mut bindings_list = HashMap::new(); + for argument in &declaration.inputs { + self.resolve_pattern(&*argument.pat, + ArgumentIrrefutableMode, + &mut bindings_list); - // Add each argument to the rib. - match optional_declaration { - None => { - // Nothing to do. - } - Some(declaration) => { - let mut bindings_list = HashMap::new(); - for argument in &declaration.inputs { - this.resolve_pattern(&*argument.pat, - ArgumentIrrefutableMode, - &mut bindings_list); + self.visit_ty(&*argument.ty); - this.resolve_type(&*argument.ty); + debug!("(resolving function) recorded argument"); + } + visit::walk_fn_ret_ty(self, &declaration.output); - debug!("(resolving function) recorded argument"); - } + // Resolve the function body. + self.visit_block(&*block); - if let ast::Return(ref ret_ty) = declaration.output { - this.resolve_type(&**ret_ty); - } - } - } - - // Resolve the function body. - this.resolve_block(&*block); - - debug!("(resolving function) leaving function"); - }); + debug!("(resolving function) leaving function"); self.label_ribs.pop(); self.value_ribs.pop(); } - fn resolve_type_parameters(&mut self, - type_parameters: &OwnedSlice) { - for type_parameter in &**type_parameters { - self.resolve_type_parameter(type_parameter); - } - } - - fn resolve_type_parameter(&mut self, - type_parameter: &TyParam) { - self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span); - for bound in &*type_parameter.bounds { - self.resolve_type_parameter_bound(type_parameter.id, bound, - TraitBoundingTypeParameter); - } - match type_parameter.default { - Some(ref ty) => self.resolve_type(&**ty), - None => {} - } - } - - fn resolve_type_parameter_bounds(&mut self, - id: NodeId, - type_parameter_bounds: &OwnedSlice, - reference_type: TraitReferenceType) { - for type_parameter_bound in &**type_parameter_bounds { - self.resolve_type_parameter_bound(id, type_parameter_bound, - reference_type); - } - } - - fn resolve_type_parameter_bound(&mut self, - id: NodeId, - type_parameter_bound: &TyParamBound, - reference_type: TraitReferenceType) { - match *type_parameter_bound { - TraitTyParamBound(ref tref, _) => { - self.resolve_poly_trait_reference(id, tref, reference_type) - } - RegionTyParamBound(..) => {} - } - } - - fn resolve_poly_trait_reference(&mut self, - id: NodeId, - poly_trait_reference: &PolyTraitRef, - reference_type: TraitReferenceType) { - self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type) - } - fn resolve_trait_reference(&mut self, id: NodeId, - trait_reference: &TraitRef, - reference_type: TraitReferenceType) { - match self.resolve_path(id, &trait_reference.path, TypeNS, true) { - None => { - let path_str = self.path_names_to_string(&trait_reference.path); - let usage_str = match reference_type { - TraitBoundingTypeParameter => "bound type parameter with", - TraitImplementation => "implement", - TraitDerivation => "derive", - TraitObject => "reference", - TraitQPath => "extract an associated item from", - }; + trait_path: &Path, + path_depth: usize) + -> Result { + if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS, true) { + if let DefTrait(_) = path_res.base_def { + debug!("(resolving trait) found trait def: {:?}", path_res); + Ok(path_res) + } else { + self.resolve_error(trait_path.span, + &format!("`{}` is not a trait", + self.path_names_to_string(trait_path, path_depth))); - let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); - self.resolve_error(trait_reference.path.span, &msg[..]); - } - Some(def) => { - match def { - (DefaultImpl(_), _) => { - debug!("(resolving trait) found trait def: {:?}", def); - self.record_def(trait_reference.ref_id, def); - } - (def, _) => { - self.resolve_error(trait_reference.path.span, - &format!("`{}` is not a trait", - self.path_names_to_string( - &trait_reference.path))); - - // If it's a typedef, give a note - if let DefTy(..) = def { - self.session.span_note( - trait_reference.path.span, - &format!("`type` aliases cannot be used for traits") - ); - } - } + // If it's a typedef, give a note + if let DefTy(..) = path_res.base_def { + self.session.span_note(trait_path.span, + "`type` aliases cannot be used for traits"); } + Err(()) } + } else { + let msg = format!("use of undeclared trait name `{}`", + self.path_names_to_string(trait_path, path_depth)); + self.resolve_error(trait_path.span, &msg[]); + Err(()) } } - fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) { - for predicate in &where_clause.predicates { + fn resolve_generics(&mut self, generics: &Generics) { + for type_parameter in &*generics.ty_params { + self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span); + } + for predicate in &generics.where_clause.predicates { match predicate { - &ast::WherePredicate::BoundPredicate(ref bound_pred) => { - self.resolve_type(&*bound_pred.bounded_ty); - - for bound in &*bound_pred.bounds { - self.resolve_type_parameter_bound(bound_pred.bounded_ty.id, bound, - TraitBoundingTypeParameter); - } - } + &ast::WherePredicate::BoundPredicate(_) | &ast::WherePredicate::RegionPredicate(_) => {} &ast::WherePredicate::EqPredicate(ref eq_pred) => { - match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) { - Some((def @ DefTyParam(..), last_private)) => { - self.record_def(eq_pred.id, (def, last_private)); - } - _ => { - self.resolve_error(eq_pred.path.span, - "undeclared associated type"); - } + let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true); + if let Some(PathResolution { base_def: DefTyParam(..), .. }) = path_res { + self.record_def(eq_pred.id, path_res.unwrap()); + } else { + self.resolve_error(eq_pred.path.span, "undeclared associated type"); } - - self.resolve_type(&*eq_pred.ty); } } } - } - - fn resolve_struct(&mut self, - id: NodeId, - generics: &Generics, - fields: &[StructField]) { - // If applicable, create a rib for the type parameters. - self.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - id, - ItemRibKind), - |this| { - // Resolve the type parameters. - this.resolve_type_parameters(&generics.ty_params); - this.resolve_where_clause(&generics.where_clause); - - // Resolve fields. - for field in fields { - this.resolve_type(&*field.node.ty); - } - }); - } - - // Does this really need to take a RibKind or is it always going - // to be NormalRibKind? - fn resolve_method(&mut self, - rib_kind: RibKind, - method: &ast::Method) { - let method_generics = method.pe_generics(); - let type_parameters = HasTypeParameters(method_generics, - FnSpace, - method.id, - rib_kind); - - if let SelfExplicit(ref typ, _) = method.pe_explicit_self().node { - self.resolve_type(&**typ); - } - - self.resolve_function(rib_kind, - Some(method.pe_fn_decl()), - type_parameters, - method.pe_body()); + visit::walk_generics(self, generics); } fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T where @@ -3303,25 +3021,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { result } - fn with_optional_trait_ref(&mut self, id: NodeId, - opt_trait_ref: &Option, + fn with_optional_trait_ref(&mut self, + opt_trait_ref: Option<&TraitRef>, f: F) -> T where F: FnOnce(&mut Resolver) -> T, { - let new_val = match *opt_trait_ref { - Some(ref trait_ref) => { - self.resolve_trait_reference(id, trait_ref, TraitImplementation); - - match self.def_map.borrow().get(&trait_ref.ref_id) { - Some(def) => { - let did = def.def_id(); - Some((did, trait_ref.clone())) - } - None => None + let mut new_val = None; + if let Some(trait_ref) = opt_trait_ref { + match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) { + Ok(path_res) => { + self.record_def(trait_ref.ref_id, path_res); + new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); } + Err(_) => { /* error was already reported */ } } - None => None - }; + visit::walk_trait_ref(self, trait_ref); + } let original_trait_ref = replace(&mut self.current_trait_ref, new_val); let result = f(self); self.current_trait_ref = original_trait_ref; @@ -3329,7 +3044,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn resolve_implementation(&mut self, - id: NodeId, generics: &Generics, opt_trait_reference: &Option, self_type: &Ty, @@ -3337,17 +3051,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If applicable, create a rib for the type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, - id, - NormalRibKind), + ItemRibKind), |this| { // Resolve the type parameters. - this.resolve_type_parameters(&generics.ty_params); - this.resolve_where_clause(&generics.where_clause); + this.visit_generics(generics); // Resolve the trait reference, if necessary. - this.with_optional_trait_ref(id, opt_trait_reference, |this| { + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this| { // Resolve the self type. - this.resolve_type(self_type); + this.visit_ty(self_type); this.with_current_self_type(self_type, |this| { for impl_item in impl_items { @@ -3360,9 +3072,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // We also need a new scope for the method- // specific type parameters. - this.resolve_method( - MethodRibKind(id, ProvidedMethod(method.id)), - &**method); + let type_parameters = + HasTypeParameters(method.pe_generics(), + FnSpace, + MethodRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_method_helper(this, &**method); + }); } TypeImplItem(ref typedef) => { // If this is a trait impl, ensure the method @@ -3370,44 +3086,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { this.check_trait_item(typedef.ident.name, typedef.span); - this.resolve_type(&*typedef.typ); + this.visit_ty(&*typedef.typ); } } } }); }); }); - - // Check that the current type is indeed a type, if we have an anonymous impl - if opt_trait_reference.is_none() { - match self_type.node { - // TyPath is the only thing that we handled in `build_reduced_graph_for_item`, - // where we created a module with the name of the type in order to implement - // an anonymous trait. In the case that the path does not resolve to an actual - // type, the result will be that the type name resolves to a module but not - // a type (shadowing any imported modules or types with this name), leading - // to weird user-visible bugs. So we ward this off here. See #15060. - TyPath(ref path, path_id) => { - match self.def_map.borrow().get(&path_id) { - // FIXME: should we catch other options and give more precise errors? - Some(&DefMod(_)) => { - self.resolve_error(path.span, "inherent implementations are not \ - allowed for types not defined in \ - the current module"); - } - _ => {} - } - } - _ => { } - } - } } fn check_trait_item(&self, name: Name, span: Span) { // If there is a TraitRef in scope for an impl, then the method must be in the trait. if let Some((did, ref trait_ref)) = self.current_trait_ref { - if self.trait_item_map.get(&(name, did)).is_none() { - let path_str = self.path_names_to_string(&trait_ref.path); + if !self.trait_item_map.contains_key(&(name, did)) { + let path_str = self.path_names_to_string(&trait_ref.path, 0); self.resolve_error(span, &format!("method `{}` is not a member of trait `{}`", token::get_name(name), @@ -3416,34 +3108,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn resolve_module(&mut self, module: &Mod, _span: Span, - _name: Name, id: NodeId) { - // Write the implementations in scope into the module metadata. - debug!("(resolving module) resolving module ID {}", id); - visit::walk_mod(self, module); - } - fn resolve_local(&mut self, local: &Local) { // Resolve the type. - if let Some(ref ty) = local.ty { - self.resolve_type(&**ty); - } + visit::walk_ty_opt(self, &local.ty); - // Resolve the initializer, if necessary. - match local.init { - None => { - // Nothing to do. - } - Some(ref initializer) => { - self.resolve_expr(&**initializer); - } - } + // Resolve the initializer. + visit::walk_expr_opt(self, &local.init); // Resolve the pattern. - let mut bindings_list = HashMap::new(); self.resolve_pattern(&*local.pat, LocalIrrefutableMode, - &mut bindings_list); + &mut HashMap::new()); } // build a map from pattern identifiers to binding-info's. @@ -3521,7 +3196,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.check_consistent_bindings(arm); visit::walk_expr_opt(self, &arm.guard); - self.resolve_expr(&*arm.body); + self.visit_expr(&*arm.body); self.value_ribs.pop(); } @@ -3573,90 +3248,63 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_type(&mut self, ty: &Ty) { match ty.node { - // Like path expressions, the interpretation of path types depends - // on whether the path has multiple elements in it or not. + // `::a::b::c` is resolved by typeck alone. + TyPath(Some(ast::QSelf { position: 0, .. }), _) => {} - TyPath(ref path, path_id) => { - // This is a path in the type namespace. Walk through scopes - // looking for it. - let mut result_def = None; + TyPath(ref maybe_qself, ref path) => { + let max_assoc_types = if let Some(ref qself) = *maybe_qself { + // Make sure the trait is valid. + let _ = self.resolve_trait_reference(ty.id, path, 1); + path.segments.len() - qself.position + } else { + path.segments.len() + }; - // First, check to see whether the name is a primitive type. - if path.segments.len() == 1 { - let id = path.segments.last().unwrap().identifier; - - match self.primitive_type_table - .primitive_types - .get(&id.name) { - - Some(&primitive_type) => { - result_def = - Some((DefPrimTy(primitive_type), LastMod(AllPublic))); - - if path.segments[0].parameters.has_lifetimes() { - span_err!(self.session, path.span, E0157, - "lifetime parameters are not allowed on this type"); - } else if !path.segments[0].parameters.is_empty() { - span_err!(self.session, path.span, E0153, - "type parameters are not allowed on this type"); - } - } - None => { - // Continue. - } + let mut resolution = None; + for depth in 0..max_assoc_types { + self.with_no_errors(|this| { + resolution = this.resolve_path(ty.id, path, depth, TypeNS, true); + }); + if resolution.is_some() { + break; } } - - if let None = result_def { - result_def = self.resolve_path(ty.id, path, TypeNS, true); + if let Some(DefMod(_)) = resolution.map(|r| r.base_def) { + // A module is not a valid type. + resolution = None; } - match result_def { + // This is a path in the type namespace. Walk through scopes + // looking for it. + match resolution { Some(def) => { // Write the result into the def map. debug!("(resolving type) writing resolution for `{}` \ (id {}) = {:?}", - self.path_names_to_string(path), - path_id, def); - self.record_def(path_id, def); + self.path_names_to_string(path, 0), + ty.id, def); + self.record_def(ty.id, def); } None => { - let msg = format!("use of undeclared type name `{}`", - self.path_names_to_string(path)); + // Keep reporting some errors even if they're ignored above. + self.resolve_path(ty.id, path, 0, TypeNS, true); + + let kind = if maybe_qself.is_some() { + "associated type" + } else { + "type name" + }; + + let msg = format!("use of undeclared {} `{}`", kind, + self.path_names_to_string(path, 0)); self.resolve_error(ty.span, &msg[..]); } } } - - TyObjectSum(ref ty, ref bound_vec) => { - self.resolve_type(&**ty); - self.resolve_type_parameter_bounds(ty.id, bound_vec, - TraitBoundingTypeParameter); - } - - 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() { - self.resolve_type(&**ty); - } - for binding in qpath.item_path.parameters.bindings() { - self.resolve_type(&*binding.ty); - } - } - - TyPolyTraitRef(ref bounds) => { - self.resolve_type_parameter_bounds( - ty.id, - bounds, - TraitObject); - visit::walk_ty(self, ty); - } - _ => { - // Just resolve embedded types. - visit::walk_ty(self, ty); - } + _ => {} } + // Resolve embedded types. + visit::walk_ty(self, ty); } fn resolve_pattern(&mut self, @@ -3683,7 +3331,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let renamed = mtwt::resolve(ident); match self.resolve_bare_identifier_pattern(ident.name, pattern.span) { - FoundStructOrEnumVariant(ref def, lp) + FoundStructOrEnumVariant(def, lp) if mode == RefutableMode => { debug!("(resolving pattern) resolving `{}` to \ struct or enum variant", @@ -3693,7 +3341,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pattern, binding_mode, "an enum variant"); - self.record_def(pattern.id, (def.clone(), lp)); + self.record_def(pattern.id, PathResolution { + base_def: def, + last_private: lp, + depth: 0 + }); } FoundStructOrEnumVariant(..) => { self.resolve_error( @@ -3703,7 +3355,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { scope", token::get_name(renamed))); } - FoundConst(ref def, lp) if mode == RefutableMode => { + FoundConst(def, lp) if mode == RefutableMode => { debug!("(resolving pattern) resolving `{}` to \ constant", token::get_name(renamed)); @@ -3712,7 +3364,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pattern, binding_mode, "a constant"); - self.record_def(pattern.id, (def.clone(), lp)); + self.record_def(pattern.id, PathResolution { + base_def: def, + last_private: lp, + depth: 0 + }); } FoundConst(..) => { self.resolve_error(pattern.span, @@ -3729,7 +3385,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // will be able to distinguish variants from // locals in patterns. - self.record_def(pattern.id, (def, LastMod(AllPublic))); + self.record_def(pattern.id, PathResolution { + base_def: def, + last_private: LastMod(AllPublic), + depth: 0 + }); // Add the binding to the local ribs, if it // doesn't already exist in the bindings list. (We @@ -3772,50 +3432,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PatEnum(ref path, _) => { // This must be an enum variant, struct or const. - match self.resolve_path(pat_id, path, ValueNS, false) { - Some(def @ (DefVariant(..), _)) | - Some(def @ (DefStruct(..), _)) | - Some(def @ (DefConst(..), _)) => { - self.record_def(pattern.id, def); - } - Some((DefStatic(..), _)) => { - self.resolve_error(path.span, - "static variables cannot be \ - referenced in a pattern, \ - use a `const` instead"); - } - Some(_) => { - self.resolve_error(path.span, - &format!("`{}` is not an enum variant, struct or const", - token::get_ident( - path.segments.last().unwrap().identifier))); - } - None => { - self.resolve_error(path.span, - &format!("unresolved enum variant, struct or const `{}`", - token::get_ident(path.segments.last().unwrap().identifier))); + if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) { + match path_res.base_def { + DefVariant(..) | DefStruct(..) | DefConst(..) => { + self.record_def(pattern.id, path_res); + } + DefStatic(..) => { + self.resolve_error(path.span, + "static variables cannot be \ + referenced in a pattern, \ + use a `const` instead"); + } + _ => { + self.resolve_error(path.span, + &format!("`{}` is not an enum variant, struct or const", + token::get_ident( + path.segments.last().unwrap().identifier))); + } } + } else { + self.resolve_error(path.span, + &format!("unresolved enum variant, struct or const `{}`", + token::get_ident(path.segments.last().unwrap().identifier))); } - - // Check the types in the path pattern. - for ty in path.segments - .iter() - .flat_map(|s| s.parameters.types().into_iter()) { - self.resolve_type(&**ty); - } - } - - PatLit(ref expr) => { - self.resolve_expr(&**expr); - } - - PatRange(ref first_expr, ref last_expr) => { - self.resolve_expr(&**first_expr); - self.resolve_expr(&**last_expr); + visit::walk_path(self, path); } PatStruct(ref path, _, _) => { - match self.resolve_path(pat_id, path, TypeNS, false) { + match self.resolve_path(pat_id, path, 0, TypeNS, false) { Some(definition) => { self.record_def(pattern.id, definition); } @@ -3823,10 +3467,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving pattern) didn't find struct \ def: {:?}", result); let msg = format!("`{}` does not name a structure", - self.path_names_to_string(path)); + self.path_names_to_string(path, 0)); self.resolve_error(path.span, &msg[..]); } } + visit::walk_path(self, path); + } + + PatLit(_) | PatRange(..) => { + visit::walk_pat(self, pattern); } _ => { @@ -3900,75 +3549,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// If `check_ribs` is true, checks the local definitions first; i.e. /// doesn't skip straight to the containing module. + /// Skips `path_depth` trailing segments, which is also reflected in the + /// returned value. See `middle::def::PathResolution` for more info. fn resolve_path(&mut self, id: NodeId, path: &Path, + path_depth: usize, namespace: Namespace, - check_ribs: bool) -> Option<(Def, LastPrivate)> { - // First, resolve the types and associated type bindings. - for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) { - self.resolve_type(&**ty); - } - for binding in path.segments.iter().flat_map(|s| s.parameters.bindings().into_iter()) { - self.resolve_type(&*binding.ty); - } + check_ribs: bool) -> Option { + let span = path.span; + let segments = &path.segments[..path.segments.len()-path_depth]; - // A special case for sugared associated type paths `T::A` where `T` is - // a type parameter and `A` is an associated type on some bound of `T`. - if namespace == TypeNS && path.segments.len() == 2 { - match self.resolve_identifier(path.segments[0].identifier, - TypeNS, - true, - path.span) { - Some((def, last_private)) => { - match def { - DefTyParam(_, _, did, _) => { - let def = DefAssociatedPath(TyParamProvenance::FromParam(did), - path.segments.last() - .unwrap().identifier); - return Some((def, last_private)); - } - DefSelfTy(nid) => { - let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)), - path.segments.last() - .unwrap().identifier); - return Some((def, last_private)); - } - _ => {} - } - } - _ => {} - } - } + let mk_res = |(def, lp)| PathResolution { + base_def: def, + last_private: lp, + depth: path_depth + }; if path.global { - return self.resolve_crate_relative_path(path, namespace); + let def = self.resolve_crate_relative_path(span, segments, namespace); + return def.map(mk_res); } // Try to find a path to an item in a module. let unqualified_def = - self.resolve_identifier(path.segments.last().unwrap().identifier, + self.resolve_identifier(segments.last().unwrap().identifier, namespace, check_ribs, - path.span); + span); - if path.segments.len() > 1 { - let def = self.resolve_module_relative_path(path, namespace); + if segments.len() > 1 { + let def = self.resolve_module_relative_path(span, segments, namespace); match (def, unqualified_def) { (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => { self.session .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, - id, - path.span, + id, span, "unnecessary qualification".to_string()); } _ => () } - return def; + def.map(mk_res) + } else { + unqualified_def.map(mk_res) } - - return unqualified_def; } // resolve a single identifier (used as a varref) @@ -3978,20 +3603,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { check_ribs: bool, span: Span) -> Option<(Def, LastPrivate)> { - if check_ribs { - match self.resolve_identifier_in_local_ribs(identifier, - namespace, - span) { - Some(def) => { - return Some((def, LastMod(AllPublic))); - } - None => { - // Continue. - } + // First, check to see whether the name is a primitive type. + if namespace == TypeNS { + if let Some(&prim_ty) = self.primitive_type_table + .primitive_types + .get(&identifier.name) { + return Some((DefPrimTy(prim_ty), LastMod(AllPublic))); } } - return self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace); + if check_ribs { + if let Some(def) = self.resolve_identifier_in_local_ribs(identifier, + namespace, + span) { + return Some((def, LastMod(AllPublic))); + } + } + + self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace) } // FIXME #4952: Merge me with resolve_name_in_module? @@ -4070,12 +3699,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // resolve a "module-relative" path, e.g. a::b::c fn resolve_module_relative_path(&mut self, - path: &Path, + span: Span, + segments: &[ast::PathSegment], namespace: Namespace) -> Option<(Def, LastPrivate)> { - let module_path = path.segments.init().iter() - .map(|ps| ps.identifier.name) - .collect::>(); + let module_path = segments.init().iter() + .map(|ps| ps.identifier.name) + .collect::>(); let containing_module; let last_private; @@ -4083,7 +3713,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match self.resolve_module_path(module, &module_path[..], UseLexicalScope, - path.span, + span, PathSearch) { Failed(err) => { let (span, msg) = match err { @@ -4091,7 +3721,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => { let msg = format!("Use of undeclared type or module `{}`", self.names_to_string(&module_path)); - (path.span, msg) + (span, msg) } }; @@ -4106,7 +3736,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - let name = path.segments.last().unwrap().identifier.name; + let name = segments.last().unwrap().identifier.name; let def = match self.resolve_definition_of_name_in_module(containing_module.clone(), name, namespace) { @@ -4127,12 +3757,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Invariant: This must be called only during main resolution, not during /// import resolution. fn resolve_crate_relative_path(&mut self, - path: &Path, + span: Span, + segments: &[ast::PathSegment], namespace: Namespace) -> Option<(Def, LastPrivate)> { - let module_path = path.segments.init().iter() - .map(|ps| ps.identifier.name) - .collect::>(); + let module_path = segments.init().iter() + .map(|ps| ps.identifier.name) + .collect::>(); let root_module = self.graph_root.get_module(); @@ -4141,7 +3772,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match self.resolve_module_path_from_root(root_module, &module_path[..], 0, - path.span, + span, PathSearch, LastMod(AllPublic)) { Failed(err) => { @@ -4150,7 +3781,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => { let msg = format!("Use of undeclared module `::{}`", self.names_to_string(&module_path[..])); - (path.span, msg) + (span, msg) } }; @@ -4169,7 +3800,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - let name = path.segments.last().unwrap().identifier.name; + let name = segments.last().unwrap().identifier.name; match self.resolve_definition_of_name_in_module(containing_module, name, namespace) { @@ -4206,10 +3837,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { local: {:?}", token::get_ident(ident), def); - return Some(def); + Some(def) } Some(DlField) | Some(DlImpl(_)) | None => { - return None; + None } } } @@ -4281,7 +3912,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks) -> Option<(Path, NodeId, FallbackChecks)> { match t.node { - TyPath(ref path, node_id) => Some((path.clone(), node_id, allow)), + TyPath(None, ref path) => Some((path.clone(), t.id, allow)), TyPtr(ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, OnlyTraitAndStatics), TyRptr(_, ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, allow), // This doesn't handle the remaining `Ty` variants as they are not @@ -4318,6 +3949,26 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + fn is_static_method(this: &Resolver, did: DefId) -> bool { + if did.krate == ast::LOCAL_CRATE { + let explicit_self = match this.ast_map.get(did.node) { + ast_map::NodeTraitItem(m) => match *m { + ast::RequiredMethod(ref m) => &m.explicit_self, + ast::ProvidedMethod(ref m) => m.pe_explicit_self(), + _ => return false + }, + ast_map::NodeImplItem(m) => match *m { + ast::MethodImplItem(ref m) => m.pe_explicit_self(), + _ => return false + }, + _ => return false + }; + explicit_self.node == ast::SelfStatic + } else { + csearch::is_static_method(&this.session.cstore, did) + } + } + let (path, node_id, allowed) = match self.current_self_type { Some(ref ty) => match extract_path_and_node_id(ty, Everything) { Some(x) => x, @@ -4328,10 +3979,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if allowed == Everything { // Look for a field with the same name in the current self_type. - match self.def_map.borrow().get(&node_id) { - Some(&DefTy(did, _)) - | Some(&DefStruct(did)) - | Some(&DefVariant(_, did, _)) => match self.structs.get(&did) { + match self.def_map.borrow().get(&node_id).map(|d| d.full_def()) { + Some(DefTy(did, _)) | + Some(DefStruct(did)) | + Some(DefVariant(_, did, _)) => match self.structs.get(&did) { None => {} Some(fields) => { if fields.iter().any(|&field_name| name == field_name) { @@ -4346,41 +3997,30 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let name_path = path.segments.iter().map(|seg| seg.identifier.name).collect::>(); // Look for a method in the current self type's impl module. - match get_module(self, path.span, &name_path[..]) { - Some(module) => match module.children.borrow().get(&name) { - Some(binding) => { - let p_str = self.path_names_to_string(&path); - match binding.def_for_namespace(ValueNS) { - Some(DefStaticMethod(_, provenance)) => { - match provenance { - FromImpl(_) => return StaticMethod(p_str), - FromTrait(_) => unreachable!() - } - } - Some(DefMethod(_, None, _)) if allowed == Everything => return Method, - Some(DefMethod(_, Some(_), _)) => return TraitItem, - _ => () + if let Some(module) = get_module(self, path.span, &name_path) { + if let Some(binding) = module.children.borrow().get(&name) { + if let Some(DefMethod(did, _)) = binding.def_for_namespace(ValueNS) { + if is_static_method(self, did) { + return StaticMethod(self.path_names_to_string(&path, 0)) + } + if self.current_trait_ref.is_some() { + return TraitItem; + } else if allowed == Everything { + return Method; } } - None => {} - }, - None => {} + } } // Look for a method in the current trait. - match self.current_trait_ref { - Some((did, ref trait_ref)) => { - let path_str = self.path_names_to_string(&trait_ref.path); - - match self.trait_item_map.get(&(name, did)) { - Some(&StaticMethodTraitItemKind) => { - return TraitMethod(path_str) - } - Some(_) => return TraitItem, - None => {} + if let Some((trait_did, ref trait_ref)) = self.current_trait_ref { + if let Some(&did) = self.trait_item_map.get(&(name, trait_did)) { + if is_static_method(self, did) { + return TraitMethod(self.path_names_to_string(&trait_ref.path, 0)); + } else { + return TraitItem; } } - None => {} } NoSuggestion @@ -4430,28 +4070,45 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Next, resolve the node. match expr.node { - // The interpretation of paths depends on whether the path has - // multiple elements in it or not. + // `::a::b::c` is resolved by typeck alone. + ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => { + let method_name = path.segments.last().unwrap().identifier.name; + let traits = self.search_for_traits_containing_method(method_name); + self.trait_map.insert(expr.id, traits); + visit::walk_expr(self, expr); + } - 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!() + ExprPath(ref maybe_qself, ref path) => { + let max_assoc_types = if let Some(ref qself) = *maybe_qself { + // Make sure the trait is valid. + let _ = self.resolve_trait_reference(expr.id, path, 1); + path.segments.len() - qself.position + } else { + path.segments.len() }; + + let mut resolution = self.with_no_errors(|this| { + this.resolve_path(expr.id, path, 0, ValueNS, true) + }); + for depth in 1..max_assoc_types { + if resolution.is_some() { + break; + } + self.with_no_errors(|this| { + resolution = this.resolve_path(expr.id, path, depth, TypeNS, true); + }); + } + if let Some(DefMod(_)) = resolution.map(|r| r.base_def) { + // A module is not a valid type or value. + resolution = None; + } + // This is a local path in the value namespace. Walk through // scopes looking for it. - match self.resolve_path(expr.id, path, ValueNS, true) { + if let Some(path_res) = resolution { // Check if struct variant - Some((DefVariant(_, _, true), _)) => { - let path_name = self.path_names_to_string(path); + if let DefVariant(_, _, true) = path_res.base_def { + let path_name = self.path_names_to_string(path, 0); self.resolve_error(expr.span, &format!("`{}` is a struct variant name, but \ this expression \ @@ -4462,86 +4119,93 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &format!("Did you mean to write: \ `{} {{ /* fields */ }}`?", path_name)); - } - Some(def) => { + } else { // Write the result into the def map. debug!("(resolving expr) resolved `{}`", - self.path_names_to_string(path)); + self.path_names_to_string(path, 0)); - self.record_def(expr.id, def); + // Partial resolutions will need the set of traits in scope, + // so they can be completed during typeck. + if path_res.depth != 0 { + let method_name = path.segments.last().unwrap().identifier.name; + let traits = self.search_for_traits_containing_method(method_name); + self.trait_map.insert(expr.id, traits); + } + + self.record_def(expr.id, path_res); } - None => { - // Be helpful if the name refers to a struct - // (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, _), _)) - if self.structs.contains_key(&struct_id) => { - self.resolve_error(expr.span, - &format!("`{}` is a structure name, but \ - this expression \ - uses it like a function name", - path_name)); + } else { + // Be helpful if the name refers to a struct + // (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, 0); + let type_res = self.with_no_errors(|this| { + this.resolve_path(expr.id, path, 0, TypeNS, false) + }); + match type_res.map(|r| r.base_def) { + Some(DefTy(struct_id, _)) + if self.structs.contains_key(&struct_id) => { + self.resolve_error(expr.span, + &format!("`{}` is a structure name, but \ + this expression \ + uses it like a function name", + path_name)); - self.session.span_help(expr.span, - &format!("Did you mean to write: \ - `{} {{ /* fields */ }}`?", - path_name)); + self.session.span_help(expr.span, + &format!("Did you mean to write: \ + `{} {{ /* fields */ }}`?", + path_name)); - } - _ => { - let mut method_scope = false; - self.value_ribs.iter().rev().all(|rib| { - let res = match *rib { - Rib { bindings: _, kind: MethodRibKind(_, _) } => true, - Rib { bindings: _, kind: ItemRibKind } => false, - _ => return true, // Keep advancing - }; + } + _ => { + // Keep reporting some errors even if they're ignored above. + self.resolve_path(expr.id, path, 0, ValueNS, true); - method_scope = res; - false // Stop advancing - }); - - if method_scope && &token::get_name(self.self_name)[..] - == path_name { - self.resolve_error( - expr.span, - "`self` is not available \ - in a static method. Maybe a \ - `self` argument is missing?"); - } else { - let last_name = path.segments.last().unwrap().identifier.name; - let mut msg = match self.find_fallback_in_self_type(last_name) { - NoSuggestion => { - // limit search to 5 to reduce the number - // of stupid suggestions - self.find_best_match_for_name(&path_name, 5) - .map_or("".to_string(), - |x| format!("`{}`", x)) - } - Field => - format!("`self.{}`", path_name), - Method - | TraitItem => - format!("to call `self.{}`", path_name), - TraitMethod(path_str) - | StaticMethod(path_str) => - format!("to call `{}::{}`", path_str, path_name) - }; - - if msg.len() > 0 { - msg = format!(". Did you mean {}?", msg) - } + let mut method_scope = false; + self.value_ribs.iter().rev().all(|rib| { + method_scope = match rib.kind { + MethodRibKind => true, + ItemRibKind | ConstantItemRibKind => false, + _ => return true, // Keep advancing + }; + false // Stop advancing + }); + if method_scope && &token::get_name(self.self_name)[..] + == path_name { self.resolve_error( expr.span, - &format!("unresolved name `{}`{}", - path_name, - msg)); + "`self` is not available \ + in a static method. Maybe a \ + `self` argument is missing?"); + } else { + let last_name = path.segments.last().unwrap().identifier.name; + let mut msg = match self.find_fallback_in_self_type(last_name) { + NoSuggestion => { + // limit search to 5 to reduce the number + // of stupid suggestions + self.find_best_match_for_name(&path_name, 5) + .map_or("".to_string(), + |x| format!("`{}`", x)) + } + Field => format!("`self.{}`", path_name), + Method | + TraitItem => + format!("to call `self.{}`", path_name), + TraitMethod(path_str) | + StaticMethod(path_str) => + format!("to call `{}::{}`", path_str, path_name) + }; + + if msg.len() > 0 { + msg = format!(". Did you mean {}?", msg) } + + self.resolve_error( + expr.span, + &format!("unresolved name `{}`{}", + path_name, msg)); } } } @@ -4550,23 +4214,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { visit::walk_expr(self, expr); } - ExprClosure(_, ref fn_decl, ref block) => { - self.resolve_function(ClosureRibKind(expr.id), - Some(&**fn_decl), NoTypeParameters, - &**block); - } - ExprStruct(ref path, _, _) => { // Resolve the path to the structure it goes to. We don't // check to ensure that the path is actually a structure; that // is checked later during typeck. - match self.resolve_path(expr.id, path, TypeNS, false) { + match self.resolve_path(expr.id, path, 0, TypeNS, false) { Some(definition) => self.record_def(expr.id, definition), - result => { - debug!("(resolving expression) didn't find struct \ - def: {:?}", result); + None => { + debug!("(resolving expression) didn't find struct def",); let msg = format!("`{}` does not name a structure", - self.path_names_to_string(path)); + self.path_names_to_string(path, 0)); self.resolve_error(path.span, &msg[..]); } } @@ -4599,7 +4256,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Some(DlDef(def @ DefLabel(_))) => { // Since this def is a label, it is never read. - self.record_def(expr.id, (def, LastMod(AllPublic))) + self.record_def(expr.id, PathResolution { + base_def: def, + last_private: LastMod(AllPublic), + depth: 0 + }) } Some(_) => { self.session.span_bug(expr.span, @@ -4675,7 +4336,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => continue }; let trait_def_id = match def { - DefaultImpl(trait_def_id) => trait_def_id, + DefTrait(trait_def_id) => trait_def_id, _ => continue, }; if self.trait_item_map.contains_key(&(name, trait_def_id)) { @@ -4691,7 +4352,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(target) => target, }; let did = match target.bindings.def_for_namespace(TypeNS) { - Some(DefaultImpl(trait_def_id)) => trait_def_id, + Some(DefTrait(trait_def_id)) => trait_def_id, Some(..) | None => continue, }; if self.trait_item_map.contains_key(&(name, did)) { @@ -4717,26 +4378,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { found_traits } - fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) { - debug!("(recording def) recording {:?} for {}, last private {:?}", - def, node_id, lp); - assert!(match lp {LastImport{..} => false, _ => true}, + fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) { + debug!("(recording def) recording {:?} for {}", resolution, node_id); + assert!(match resolution.last_private {LastImport{..} => false, _ => true}, "Import should only be used for `use` directives"); - self.last_private.insert(node_id, lp); - match self.def_map.borrow_mut().entry(node_id) { - // Resolve appears to "resolve" the same ID multiple - // times, so here is a sanity check it at least comes to - // the same conclusion! - nmatsakis - Occupied(entry) => if def != *entry.get() { - self.session - .bug(&format!("node_id {} resolved first to {:?} and \ - then {:?}", - node_id, - *entry.get(), - def)); - }, - Vacant(entry) => { entry.insert(def); }, + if let Some(prev_res) = self.def_map.borrow_mut().insert(node_id, resolution) { + let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP); + self.session.span_bug(span, &format!("path resolved multiple times \ + ({:?} before, {:?} now)", + prev_res, resolution)); } } @@ -4831,7 +4482,6 @@ pub struct CrateMap { pub export_map: ExportMap, pub trait_map: TraitMap, pub external_exports: ExternalExports, - pub last_private_map: LastPrivateMap, pub glob_map: Option } @@ -4870,7 +4520,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, export_map: resolver.export_map, trait_map: resolver.trait_map, external_exports: resolver.external_exports, - last_private_map: resolver.last_private, glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 591450a2595..371b9268fba 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -218,7 +218,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref", ref_id)); } - let def = (*self.analysis.ty_cx.def_map.borrow())[ref_id]; + let def = self.analysis.ty_cx.def_map.borrow()[ref_id].full_def(); match def { def::DefPrimTy(_) => None, _ => Some(def.def_id()), @@ -231,15 +231,14 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind", ref_id)); } - let def = (*def_map)[ref_id]; + let def = def_map[ref_id].full_def(); match def { def::DefMod(_) | def::DefForeignMod(_) => Some(recorder::ModRef), def::DefStruct(_) => Some(recorder::StructRef), def::DefTy(..) | def::DefAssociatedTy(..) | - def::DefAssociatedPath(..) | - def::DefaultImpl(_) => Some(recorder::TypeRef), + def::DefTrait(_) => Some(recorder::TypeRef), def::DefStatic(_, _) | def::DefConst(_) | def::DefLocal(_) | @@ -250,9 +249,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefSelfTy(_) | def::DefRegion(_) | - def::DefTyParamBinder(_) | def::DefLabel(_) | - def::DefStaticMethod(..) | def::DefTyParam(..) | def::DefUse(_) | def::DefMethod(..) | @@ -662,9 +659,9 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id)); match typ.node { // Common case impl for a struct or something basic. - ast::TyPath(ref path, id) => { + ast::TyPath(None, ref path) => { let sub_span = self.span.sub_span_for_type_name(path.span); - let self_id = self.lookup_type_ref(id).map(|id| { + let self_id = self.lookup_type_ref(typ.id).map(|id| { self.fmt.ref_str(recorder::TypeRef, path.span, sub_span, @@ -795,9 +792,9 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { self.sess.span_bug(span, &format!("def_map has no key for {} in visit_expr", id)); } - let def = &(*def_map)[id]; + let def = def_map[id].full_def(); let sub_span = self.span.span_for_last_ident(span); - match *def { + match def { def::DefUpvar(..) | def::DefLocal(..) | def::DefStatic(..) | @@ -817,8 +814,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { sub_span, def_id, self.cur_scope), - def::DefStaticMethod(declid, provenence) | - def::DefMethod(declid, _, provenence) => { + def::DefMethod(declid, provenence) => { let sub_span = self.span.sub_span_for_meth_name(span); let defid = if declid.krate == ast::LOCAL_CRATE { let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, @@ -870,11 +866,18 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { &format!("Unexpected def kind while looking \ up path in `{}`: `{:?}`", self.span.snippet(span), - *def)), + def)), } // modules or types in the path prefix - match *def { - def::DefStaticMethod(..) => self.write_sub_path_trait_truncated(path), + match def { + def::DefMethod(did, _) => { + let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, did); + if let ty::MethodTraitItem(m) = ti { + if m.explicit_self == ty::StaticExplicitSelfCategory { + self.write_sub_path_trait_truncated(path); + } + } + } def::DefLocal(_) | def::DefStatic(_,_) | def::DefConst(..) | @@ -1001,7 +1004,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef)); visit::walk_path(self, path); - let def = self.analysis.ty_cx.def_map.borrow()[p.id]; + let def = self.analysis.ty_cx.def_map.borrow()[p.id].full_def(); let struct_def = match def { def::DefConst(..) => None, def::DefVariant(_, variant_id, _) => Some(variant_id), @@ -1303,8 +1306,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } match t.node { - ast::TyPath(ref path, id) => { - match self.lookup_type_ref(id) { + ast::TyPath(_, ref path) => { + match self.lookup_type_ref(t.id) { Some(id) => { let sub_span = self.span.sub_span_for_type_name(t.span); self.fmt.ref_str(recorder::TypeRef, @@ -1334,16 +1337,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { // Don't need to do anything for function calls, // because just walking the callee path does what we want. visit::walk_expr(self, ex); - }, - ast::ExprPath(ref path) => { - 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::ExprPath(_, ref path) => { + self.process_path(ex.id, path.span, path, None); + visit::walk_expr(self, ex); } ast::ExprStruct(ref path, ref fields, ref base) => self.process_struct_lit(ex, path, fields, base), @@ -1459,8 +1456,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { &format!("def_map has no key for {} in visit_arm", id)); } - let def = &(*def_map)[id]; - match *def { + let def = def_map[id].full_def(); + match def { def::DefLocal(id) => { let value = if *immut { self.span.snippet(p.span).to_string() @@ -1483,7 +1480,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { def::DefStatic(_, _) => {} def::DefConst(..) => {} _ => error!("unexpected definition kind when processing collected paths: {:?}", - *def) + def) } } for &(id, ref path, ref_kind) in &paths_to_process { diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index a5bebaa257c..8de046fa6eb 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -238,6 +238,7 @@ impl<'a> SpanUtils<'a> { let mut toks = self.retokenise_span(span); // We keep track of how many brackets we're nested in let mut bracket_count = 0; + let mut found_ufcs_sep = false; loop { let ts = toks.real_token(); if ts.tok == token::Eof { @@ -254,13 +255,20 @@ impl<'a> SpanUtils<'a> { } bracket_count += match ts.tok { token::Lt => 1, - token::Gt => -1, + token::Gt => { + // Ignore the `>::` in `::AssocTy`. + if !found_ufcs_sep && bracket_count == 0 { + found_ufcs_sep = true; + 0 + } else { + -1 + } + } token::BinOp(token::Shl) => 2, token::BinOp(token::Shr) => -2, _ => 0 }; - if ts.tok.is_ident() && - bracket_count == nesting { + if ts.tok.is_ident() && bracket_count == nesting { result.push(self.make_sub_span(span, Some(ts.sp)).unwrap()); } } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 26e1a981f1b..9a121a8830b 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -598,7 +598,7 @@ fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } ast::PatIdent(..) | ast::PatEnum(..) | ast::PatStruct(..) => { // This is either an enum variant or a variable binding. - let opt_def = tcx.def_map.borrow().get(&cur.id).cloned(); + let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def()); match opt_def { Some(def::DefVariant(enum_id, var_id, _)) => { let variant = ty::enum_variant_with_id(tcx, enum_id, var_id); @@ -725,14 +725,14 @@ fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: uint) -> bool { match pat.node { ast::PatTup(_) => true, ast::PatStruct(..) => { - match tcx.def_map.borrow().get(&pat.id) { - Some(&def::DefVariant(..)) => false, + match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(def::DefVariant(..)) => false, _ => true, } } ast::PatEnum(..) | ast::PatIdent(_, _, None) => { - match tcx.def_map.borrow().get(&pat.id) { - Some(&def::DefStruct(..)) => true, + match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(def::DefStruct(..)) => true, _ => false } } @@ -1277,20 +1277,20 @@ pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Checks whether the binding in `discr` is assigned to anywhere in the expression `body` fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool { let (vid, field) = match discr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => match bcx.def(discr.id) { + ast::ExprPath(..) => match bcx.def(discr.id) { def::DefLocal(vid) | def::DefUpvar(vid, _) => (vid, None), _ => return false }, ast::ExprField(ref base, field) => { - let vid = match bcx.tcx().def_map.borrow().get(&base.id) { - Some(&def::DefLocal(vid)) | Some(&def::DefUpvar(vid, _)) => vid, + let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) { + Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _)) => vid, _ => return false }; (vid, Some(mc::NamedField(field.node.name))) }, ast::ExprTupField(ref base, field) => { - let vid = match bcx.tcx().def_map.borrow().get(&base.id) { - Some(&def::DefLocal(vid)) | Some(&def::DefUpvar(vid, _)) => vid, + let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) { + Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _)) => vid, _ => return false }; (vid, Some(mc::PositionalField(field.node))) @@ -1689,7 +1689,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } ast::PatEnum(_, ref sub_pats) => { - let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).cloned(); + let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def()); match opt_def { Some(def::DefVariant(enum_id, var_id, _)) => { let repr = adt::represent_node(bcx, pat.id); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index a358a3d89e9..59fcd5492eb 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -93,7 +93,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) // pick out special kinds of expressions that can be called: match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { return trans_def(bcx, bcx.def(expr.id), expr); } _ => {} @@ -165,13 +165,11 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) } } - def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) | - def::DefStaticMethod(did, def::FromImpl(_)) => { + def::DefFn(did, _) | def::DefMethod(did, def::FromImpl(_)) => { fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), bcx.fcx.param_substs).val) } - def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) | - def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => { + def::DefMethod(meth_did, def::FromTrait(trait_did)) => { fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(), meth_did, trait_did, @@ -207,11 +205,10 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) def::DefUpvar(..) => { datum_callee(bcx, ref_expr) } - def::DefMod(..) | def::DefForeignMod(..) | def::DefaultImpl(..) | + def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) | def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) | - def::DefUse(..) | def::DefTyParamBinder(..) | - def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) | - def::DefSelfTy(..) | def::DefAssociatedPath(..) => { + def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) | + def::DefTyParam(..) | def::DefSelfTy(..) => { bcx.tcx().sess.span_bug( ref_expr.span, &format!("cannot translate def {:?} \ diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index a3ba506fc46..d8fc6df2685 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -603,7 +603,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { pub fn def(&self, nid: ast::NodeId) -> def::Def { match self.tcx().def_map.borrow().get(&nid) { - Some(v) => v.clone(), + Some(v) => v.full_def(), None => { self.tcx().sess.bug(&format!( "no def associated with node id {}", nid)); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 5cbe9dd71fb..c1d22cc973c 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -193,8 +193,8 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> ValueRef { // Special-case constants to cache a common global for all uses. match expr.node { - ast::ExprPath(_) => { - let def = ccx.tcx().def_map.borrow()[expr.id]; + ast::ExprPath(..) => { + let def = ccx.tcx().def_map.borrow()[expr.id].full_def(); match def { def::DefConst(def_id) => { if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) { @@ -582,7 +582,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, _ => break, } } - let opt_def = cx.tcx().def_map.borrow().get(&cur.id).cloned(); + let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def()); if let Some(def::DefStatic(def_id, _)) = opt_def { get_static_val(cx, def_id, ety) } else { @@ -663,10 +663,10 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, C_array(llunitty, &vs[..]) } } - ast::ExprPath(_) | ast::ExprQPath(_) => { - let def = cx.tcx().def_map.borrow()[e.id]; + ast::ExprPath(..) => { + let def = cx.tcx().def_map.borrow()[e.id].full_def(); match def { - def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => { + def::DefFn(..) | def::DefMethod(..) => { expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } def::DefConst(def_id) => { @@ -701,7 +701,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ast::ExprCall(ref callee, ref args) => { - let opt_def = cx.tcx().def_map.borrow().get(&callee.id).cloned(); + let opt_def = cx.tcx().def_map.borrow().get(&callee.id).map(|d| d.full_def()); let arg_vals = map_list(&args[..]); match opt_def { Some(def::DefStruct(_)) => { diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 5eebe6a4a05..ad96c506c9d 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -306,11 +306,10 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let loop_id = match opt_label { None => fcx.top_loop_scope(), Some(_) => { - match bcx.tcx().def_map.borrow().get(&expr.id) { - Some(&def::DefLabel(loop_id)) => loop_id, - ref r => { - bcx.tcx().sess.bug(&format!("{:?} in def-map for label", - r)) + match bcx.tcx().def_map.borrow().get(&expr.id).map(|d| d.full_def()) { + Some(def::DefLabel(loop_id)) => loop_id, + r => { + bcx.tcx().sess.bug(&format!("{:?} in def-map for label", r)) } } } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 162881f58c7..d70a904b811 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3487,8 +3487,7 @@ fn create_scope_map(cx: &CrateContext, ast::ExprLit(_) | ast::ExprBreak(_) | ast::ExprAgain(_) | - ast::ExprPath(_) | - ast::ExprQPath(_) => {} + ast::ExprPath(..) => {} ast::ExprCast(ref sub_exp, _) | ast::ExprAddrOf(_, ref sub_exp) | diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 9e9ee453752..5cc1baf66c6 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -143,7 +143,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // it prefers in-place instantiation, likely because it contains // `[x; N]` somewhere within. match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { match bcx.def(expr.id) { def::DefConst(did) => { let expr = consts::get_const_expr(bcx.ccx(), did, expr); @@ -629,7 +629,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprParen(ref e) => { trans(bcx, &**e) } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { trans_def(bcx, expr, bcx.def(expr.id)) } ast::ExprField(ref base, ident) => { @@ -875,7 +875,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_def_lvalue"); match def { - def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) | + def::DefFn(..) | def::DefMethod(..) | def::DefStruct(_) | def::DefVariant(..) => { let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def, bcx.fcx.param_substs); @@ -1033,7 +1033,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprParen(ref e) => { trans_into(bcx, &**e, dest) } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest) } ast::ExprIf(ref cond, ref thn, ref els) => { @@ -1275,12 +1275,10 @@ pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, match def { def::DefFn(did, _) | def::DefStruct(did) | def::DefVariant(_, did, _) | - def::DefStaticMethod(did, def::FromImpl(_)) | - def::DefMethod(did, _, def::FromImpl(_)) => { + def::DefMethod(did, def::FromImpl(_)) => { callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs) } - def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) | - def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => { + def::DefMethod(impl_did, def::FromTrait(trait_did)) => { meth::trans_static_method_callee(ccx, impl_did, trait_did, ref_expr.id, param_substs) @@ -1365,7 +1363,7 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, ty.repr(tcx))); } Some(node_id) => { - let def = tcx.def_map.borrow()[node_id].clone(); + let def = tcx.def_map.borrow()[node_id].full_def(); match def { def::DefVariant(enum_id, variant_id, _) => { let variant_info = ty::enum_variant_with_id( diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 581279c2c9c..9e50fdb4c48 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -48,22 +48,23 @@ //! case but `&a` in the second. Basically, defaults that appear inside //! an rptr (`&r.T`) use the region `r` that appears in the rptr. -use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS}; +use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS}; use middle::const_eval; use middle::def; use middle::resolve_lifetime as rl; +use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; -use TypeAndSubsts; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::DefIdMap; use util::ppaux::{self, Repr, UserString}; -use std::rc::Rc; use std::iter::{repeat, AdditiveIterator}; +use std::rc::Rc; +use std::slice; use syntax::{abi, ast, ast_util}; use syntax::codemap::Span; use syntax::parse::token; @@ -245,8 +246,10 @@ pub fn opt_ast_region_to_region<'tcx>( pub fn ast_path_substs_for_ty<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, decl_generics: &ty::Generics<'tcx>, - path: &ast::Path) + item_segment: &ast::PathSegment) -> Substs<'tcx> { let tcx = this.tcx(); @@ -262,27 +265,36 @@ pub fn ast_path_substs_for_ty<'tcx>( assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); assert!(decl_generics.types.all(|d| d.space != FnSpace)); - let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters { + let (regions, types, assoc_bindings) = match item_segment.parameters { ast::AngleBracketedParameters(ref data) => { - convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data) + convert_angle_bracketed_parameters(this, rscope, span, decl_generics, data) } ast::ParenthesizedParameters(ref data) => { - span_err!(tcx.sess, path.span, E0214, + span_err!(tcx.sess, span, E0214, "parenthesized parameters may only be used with a trait"); - convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data) + convert_parenthesized_parameters(this, rscope, span, decl_generics, data) } }; prohibit_projections(this.tcx(), &assoc_bindings); create_substs_for_ast_path(this, - path.span, + span, + param_mode, decl_generics, None, types, regions) } +#[derive(PartialEq, Eq)] +pub enum PathParamMode { + // Any path in a type context. + Explicit, + // The `module::Type` in `module::Type::method` in an expression. + Optional +} + fn create_region_substs<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, @@ -330,6 +342,7 @@ fn create_region_substs<'tcx>( fn create_substs_for_ast_path<'tcx>( this: &AstConv<'tcx>, span: Span, + param_mode: PathParamMode, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types_provided: Vec>, @@ -348,13 +361,21 @@ fn create_substs_for_ast_path<'tcx>( // Convert the type parameters supplied by the user. let ty_param_defs = decl_generics.types.get_slice(TypeSpace); - let supplied_ty_param_count = types_provided.len(); let formal_ty_param_count = ty_param_defs.len(); let required_ty_param_count = ty_param_defs.iter() .take_while(|x| x.default.is_none()) .count(); - let mut type_substs = types_provided; + // Fill with `ty_infer` if no params were specified, as long as + // they were optional (e.g. paths inside expressions). + let mut type_substs = if param_mode == PathParamMode::Optional && + types_provided.is_empty() { + (0..formal_ty_param_count).map(|_| this.ty_infer(span)).collect() + } else { + types_provided + }; + + let supplied_ty_param_count = type_substs.len(); check_type_argument_count(this.tcx(), span, supplied_ty_param_count, required_ty_param_count, formal_ty_param_count); @@ -414,7 +435,7 @@ fn create_substs_for_ast_path<'tcx>( } } - return substs; + substs } struct ConvertedBinding<'tcx> { @@ -574,9 +595,9 @@ pub fn instantiate_poly_trait_ref<'tcx>( // lifetimes. Oh well, not there yet. let shifted_rscope = ShiftedRscope::new(rscope); - let trait_ref = - instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref, - self_ty, Some(&mut projections)); + let trait_ref = instantiate_trait_ref(this, &shifted_rscope, + &ast_trait_ref.trait_ref, + None, self_ty, Some(&mut projections)); for projection in projections { poly_projections.push(ty::Binder(projection)); @@ -594,26 +615,31 @@ pub fn instantiate_poly_trait_ref<'tcx>( pub fn instantiate_trait_ref<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, - ast_trait_ref: &ast::TraitRef, + trait_ref: &ast::TraitRef, + impl_id: Option, self_ty: Option>, projections: Option<&mut Vec>>) -> Rc> { - match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { - def::DefaultImpl(trait_def_id) => { + let path = &trait_ref.path; + match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) { + def::DefTrait(trait_def_id) => { let trait_ref = ast_path_to_trait_ref(this, rscope, + path.span, + PathParamMode::Explicit, trait_def_id, self_ty, - &ast_trait_ref.path, + path.segments.last().unwrap(), projections); - this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone()); + if let Some(id) = impl_id { + this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone()); + } trait_ref } _ => { - span_fatal!(this.tcx().sess, ast_trait_ref.path.span, E0245, - "`{}` is not a trait", - ast_trait_ref.path.user_string(this.tcx())); + span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait", + path.user_string(this.tcx())); } } } @@ -621,8 +647,10 @@ pub fn instantiate_trait_ref<'tcx>( fn object_path_to_poly_trait_ref<'a,'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, trait_def_id: ast::DefId, - path: &ast::Path, + trait_segment: &ast::PathSegment, mut projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { @@ -633,9 +661,11 @@ fn object_path_to_poly_trait_ref<'a,'tcx>( let mut tmp = Vec::new(); let trait_ref = ty::Binder(ast_path_to_trait_ref(this, &shifted_rscope, + span, + param_mode, trait_def_id, None, - path, + trait_segment, Some(&mut tmp))); projections.extend(tmp.into_iter().map(ty::Binder)); trait_ref @@ -644,48 +674,51 @@ fn object_path_to_poly_trait_ref<'a,'tcx>( fn ast_path_to_trait_ref<'a,'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, trait_def_id: ast::DefId, self_ty: Option>, - path: &ast::Path, + trait_segment: &ast::PathSegment, mut projections: Option<&mut Vec>>) -> Rc> { - debug!("ast_path_to_trait_ref {:?}", path); + debug!("ast_path_to_trait_ref {:?}", trait_segment); let trait_def = this.get_trait_def(trait_def_id); - let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters { + let (regions, types, assoc_bindings) = match trait_segment.parameters { ast::AngleBracketedParameters(ref data) => { // For now, require that parenthetical notation be used // only with `Fn()` etc. if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar { - span_err!(this.tcx().sess, path.span, E0215, + span_err!(this.tcx().sess, span, E0215, "angle-bracket notation is not stable when \ used with the `Fn` family of traits, use parentheses"); - span_help!(this.tcx().sess, path.span, + span_help!(this.tcx().sess, span, "add `#![feature(unboxed_closures)]` to \ the crate attributes to enable"); } - convert_angle_bracketed_parameters(this, rscope, path.span, &trait_def.generics, data) + convert_angle_bracketed_parameters(this, rscope, span, &trait_def.generics, data) } ast::ParenthesizedParameters(ref data) => { // For now, require that parenthetical notation be used // only with `Fn()` etc. if !this.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar { - span_err!(this.tcx().sess, path.span, E0216, + span_err!(this.tcx().sess, span, E0216, "parenthetical notation is only stable when \ used with the `Fn` family of traits"); - span_help!(this.tcx().sess, path.span, + span_help!(this.tcx().sess, span, "add `#![feature(unboxed_closures)]` to \ the crate attributes to enable"); } - convert_parenthesized_parameters(this, rscope, path.span, &trait_def.generics, data) + convert_parenthesized_parameters(this, rscope, span, &trait_def.generics, data) } }; let substs = create_substs_for_ast_path(this, - path.span, + span, + param_mode, &trait_def.generics, self_ty, types, @@ -818,78 +851,31 @@ fn ast_type_binding_to_projection_predicate<'tcx>( }) } -pub fn ast_path_to_ty<'tcx>( +fn ast_path_to_ty<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, did: ast::DefId, - path: &ast::Path) - -> TypeAndSubsts<'tcx> + item_segment: &ast::PathSegment) + -> Ty<'tcx> { - let tcx = this.tcx(); let ty::TypeScheme { generics, ty: decl_ty } = this.get_item_type_scheme(did); - let substs = ast_path_substs_for_ty(this, - rscope, - &generics, - path); - let ty = decl_ty.subst(tcx, &substs); - TypeAndSubsts { substs: substs, ty: ty } -} + let substs = ast_path_substs_for_ty(this, rscope, + span, param_mode, + &generics, item_segment); -/// Converts the given AST type to a built-in type. A "built-in type" is, at -/// present, either a core numeric type, a string, or `Box`. -pub fn ast_ty_to_builtin_ty<'tcx>( - this: &AstConv<'tcx>, - rscope: &RegionScope, - ast_ty: &ast::Ty) - -> Option> { - match ast_ty_to_prim_ty(this.tcx(), ast_ty) { - Some(typ) => return Some(typ), - None => {} + // FIXME(#12938): This is a hack until we have full support for DST. + if Some(did) == this.tcx().lang_items.owned_box() { + assert_eq!(substs.types.len(TypeSpace), 1); + return ty::mk_uniq(this.tcx(), *substs.types.get(TypeSpace, 0)); } - match ast_ty.node { - ast::TyPath(ref path, id) => { - let a_def = match this.tcx().def_map.borrow().get(&id) { - None => { - this.tcx() - .sess - .span_bug(ast_ty.span, - &format!("unbound path {}", - path.repr(this.tcx()))) - } - Some(&d) => d - }; - - // FIXME(#12938): This is a hack until we have full support for - // DST. - match a_def { - def::DefTy(did, _) | - def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => { - let ty = ast_path_to_ty(this, rscope, did, path).ty; - match ty.sty { - ty::ty_struct(struct_def_id, ref substs) => { - assert_eq!(struct_def_id, did); - assert_eq!(substs.types.len(TypeSpace), 1); - let referent_ty = *substs.types.get(TypeSpace, 0); - Some(ty::mk_uniq(this.tcx(), referent_ty)) - } - _ => { - this.tcx().sess.span_bug( - path.span, - &format!("converting `Box` to `{}`", - ty.repr(this.tcx()))); - } - } - } - _ => None - } - } - _ => None - } + decl_ty.subst(this.tcx(), &substs) } type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); @@ -912,14 +898,20 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, */ match ty.node { - ast::TyPath(ref path, id) => { - match this.tcx().def_map.borrow().get(&id) { - Some(&def::DefaultImpl(trait_def_id)) => { + ast::TyPath(None, ref path) => { + let def = match this.tcx().def_map.borrow().get(&ty.id) { + Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def), + _ => None + }; + match def { + Some(def::DefTrait(trait_def_id)) => { let mut projection_bounds = Vec::new(); let trait_ref = object_path_to_poly_trait_ref(this, rscope, + path.span, + PathParamMode::Explicit, trait_def_id, - path, + path.segments.last().unwrap(), &mut projection_bounds); Ok((trait_ref, projection_bounds)) } @@ -983,21 +975,40 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, } fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, - ast_ty: &ast::Ty, - provenance: def::TyParamProvenance, - assoc_name: ast::Name) - -> Ty<'tcx> + span: Span, + ty: Ty<'tcx>, + ty_path_def: def::Def, + item_segment: &ast::PathSegment) + -> (Ty<'tcx>, def::Def) { let tcx = this.tcx(); - let ty_param_def_id = provenance.def_id(); + check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); + let assoc_name = item_segment.identifier.name; + + let is_param = match (&ty.sty, ty_path_def) { + (&ty::ty_param(_), def::DefTyParam(..)) | + (&ty::ty_param(_), def::DefSelfTy(_)) => true, + _ => false + }; + + let ty_param_node_id = if is_param { + ty_path_def.local_node_id() + } else { + span_err!(tcx.sess, span, E0223, + "ambiguous associated type; specify the type using the syntax \ + `<{} as Trait>::{}`", + ty.user_string(tcx), token::get_name(assoc_name)); + return (tcx.types.err, ty_path_def); + }; let mut suitable_bounds: Vec<_>; let ty_param_name: ast::Name; { // contain scope of refcell: let ty_param_defs = tcx.ty_param_defs.borrow(); - let ty_param_def = &ty_param_defs[ty_param_def_id.node]; + let ty_param_def = &ty_param_defs[ty_param_node_id]; ty_param_name = ty_param_def.name; + // FIXME(#20300) -- search where clauses, not bounds suitable_bounds = traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds) @@ -1006,21 +1017,21 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } if suitable_bounds.len() == 0 { - span_err!(tcx.sess, ast_ty.span, E0220, + span_err!(tcx.sess, span, E0220, "associated type `{}` not found for type parameter `{}`", token::get_name(assoc_name), token::get_name(ty_param_name)); - return this.tcx().types.err; + return (this.tcx().types.err, ty_path_def); } if suitable_bounds.len() > 1 { - span_err!(tcx.sess, ast_ty.span, E0221, + span_err!(tcx.sess, span, E0221, "ambiguous associated type `{}` in bounds of `{}`", token::get_name(assoc_name), token::get_name(ty_param_name)); for suitable_bound in &suitable_bounds { - span_note!(this.tcx().sess, ast_ty.span, + span_note!(this.tcx().sess, span, "associated type `{}` could derive from `{}`", token::get_name(ty_param_name), suitable_bound.user_string(this.tcx())); @@ -1028,7 +1039,32 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } let suitable_bound = suitable_bounds.pop().unwrap().clone(); - return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name); + let trait_did = suitable_bound.0.def_id; + + let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name); + + let item_did = if trait_did.krate == ast::LOCAL_CRATE { + // `ty::trait_items` used below requires information generated + // by type collection, which may be in progress at this point. + match this.tcx().map.expect_item(trait_did.node).node { + ast::ItemTrait(_, _, _, ref trait_items) => { + trait_items.iter().filter_map(|i| { + if let ast::TypeTraitItem(ref assoc) = *i { + if assoc.ty_param.ident.name == assoc_name { + return Some(ast_util::local_def(assoc.ty_param.id)); + } + } + None + }).next().expect("missing associated type") + } + _ => unreachable!() + } + } else { + let trait_items = ty::trait_items(this.tcx(), trait_did); + let item = trait_items.iter().find(|i| i.name() == assoc_name); + item.expect("missing associated type").def_id() + }; + (ty, def::DefAssociatedTy(trait_did, item_did)) } fn trait_defines_associated_type_named(this: &AstConv, @@ -1043,31 +1079,43 @@ fn trait_defines_associated_type_named(this: &AstConv, fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, rscope: &RegionScope, - ast_ty: &ast::Ty, // the TyQPath - qpath: &ast::QPath) + span: Span, + param_mode: PathParamMode, + opt_self_ty: Option>, + trait_def_id: ast::DefId, + trait_segment: &ast::PathSegment, + item_segment: &ast::PathSegment) -> Ty<'tcx> { - debug!("qpath_to_ty(ast_ty={})", - ast_ty.repr(this.tcx())); + let tcx = this.tcx(); - let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type); + check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); - debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx())); + let self_ty = if let Some(ty) = opt_self_ty { + ty + } else { + let path_str = ty::item_path_str(tcx, trait_def_id); + span_err!(tcx.sess, span, E0223, + "ambiguous associated type; specify the type using the syntax \ + `::{}`", + path_str, &token::get_ident(item_segment.identifier)); + return tcx.types.err; + }; - let trait_ref = instantiate_trait_ref(this, + debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); + + let trait_ref = ast_path_to_trait_ref(this, rscope, - &*qpath.trait_ref, - Some(self_type), + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment, None); - debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx())); + debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); - // `::U` shouldn't parse right now. - assert!(qpath.item_path.parameters.is_empty()); - - return this.projected_ty(ast_ty.span, - trait_ref, - qpath.item_path.identifier.name); + this.projected_ty(span, trait_ref, item_segment.identifier.name) } /// Convert a type supplied as value for a type argument from AST into our @@ -1103,6 +1151,96 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, } } +pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &mut def::Def, + opt_self_ty: Option>, + segments: &[ast::PathSegment], + assoc_segments: &[ast::PathSegment]) + -> Ty<'tcx> { + let tcx = this.tcx(); + + let base_ty = match *def { + def::DefTrait(trait_def_id) => { + // N.B. this case overlaps somewhat with + // TyObjectSum, see that fn for details + let mut projection_bounds = Vec::new(); + + let trait_ref = object_path_to_poly_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + segments.last().unwrap(), + &mut projection_bounds); + + check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS); + trait_ref_to_object_type(this, rscope, span, trait_ref, + projection_bounds, &[]) + } + def::DefTy(did, _) | def::DefStruct(did) => { + check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS); + ast_path_to_ty(this, rscope, span, + param_mode, did, + segments.last().unwrap()) + } + def::DefTyParam(space, index, _, name) => { + check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + ty::mk_param(tcx, space, index, name) + } + def::DefSelfTy(_) => { + // n.b.: resolve guarantees that the this type only appears in a + // trait, which we rely upon in various places when creating + // substs + check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + ty::mk_self_type(tcx) + } + def::DefAssociatedTy(trait_did, _) => { + check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS); + qpath_to_ty(this, rscope, span, param_mode, + opt_self_ty, trait_did, + &segments[segments.len()-2], + segments.last().unwrap()) + } + def::DefMod(id) => { + // Used as sentinel by callers to indicate the `::A::B::C` form. + // FIXME(#22519) This part of the resolution logic should be + // avoided entirely for that form, once we stop needed a Def + // for `associated_path_def_to_ty`. + if segments.is_empty() { + opt_self_ty.expect("missing T in ::a::b::c") + } else { + tcx.sess.span_bug(span, + &format!("found module name used as a type: {}", + tcx.map.node_to_string(id.node))); + } + } + def::DefPrimTy(prim_ty) => { + prim_ty_to_ty(tcx, segments, prim_ty) + } + _ => { + span_fatal!(tcx.sess, span, E0248, + "found value name used as a type: {:?}", *def); + } + }; + + // If any associated type segments remain, attempt to resolve them. + let mut ty = base_ty; + for segment in assoc_segments { + if ty.sty == ty::ty_err { + break; + } + // This is pretty bad (it will fail except for T::A and Self::A). + let (a_ty, a_def) = associated_path_def_to_ty(this, span, + ty, *def, segment); + ty = a_ty; + *def = a_def; + } + ty +} + /// Parses the programmer's textual representation of a type into our /// internal notion of a type. pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, @@ -1129,173 +1267,128 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved); drop(ast_ty_to_ty_cache); - let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| { - match ast_ty.node { - ast::TyVec(ref ty) => { - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None) - } - ast::TyObjectSum(ref ty, ref bounds) => { - match ast_ty_to_trait_ref(this, rscope, &**ty, &bounds[..]) { - Ok((trait_ref, projection_bounds)) => { - trait_ref_to_object_type(this, - rscope, - ast_ty.span, - trait_ref, - projection_bounds, - &bounds[..]) - } - Err(ErrorReported) => { - this.tcx().types.err - } + let typ = match ast_ty.node { + ast::TyVec(ref ty) => { + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None) + } + ast::TyObjectSum(ref ty, ref bounds) => { + match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) { + Ok((trait_ref, projection_bounds)) => { + trait_ref_to_object_type(this, + rscope, + ast_ty.span, + trait_ref, + projection_bounds, + bounds) } - } - ast::TyPtr(ref mt) => { - ty::mk_ptr(tcx, ty::mt { - ty: ast_ty_to_ty(this, rscope, &*mt.ty), - mutbl: mt.mutbl - }) - } - ast::TyRptr(ref region, ref mt) => { - let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region); - debug!("ty_rptr r={}", r.repr(this.tcx())); - let rscope1 = - &ObjectLifetimeDefaultRscope::new( - rscope, - Some(ty::ObjectLifetimeDefault::Specific(r))); - let t = ast_ty_to_ty(this, rscope1, &*mt.ty); - ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) - } - ast::TyTup(ref fields) => { - let flds = fields.iter() - .map(|t| ast_ty_to_ty(this, rscope, &**t)) - .collect(); - ty::mk_tup(tcx, flds) - } - ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), - ast::TyBareFn(ref bf) => { - if bf.decl.variadic && bf.abi != abi::C { - span_err!(tcx.sess, ast_ty.span, E0222, - "variadic function must have C calling convention"); + Err(ErrorReported) => { + this.tcx().types.err } - let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); - ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn)) - } - ast::TyPolyTraitRef(ref bounds) => { - conv_ty_poly_trait_ref(this, rscope, ast_ty.span, &bounds[..]) - } - ast::TyPath(ref path, id) => { - let a_def = match tcx.def_map.borrow().get(&id) { - None => { - tcx.sess - .span_bug(ast_ty.span, - &format!("unbound path {}", - path.repr(tcx))) - } - Some(&d) => d - }; - match a_def { - def::DefaultImpl(trait_def_id) => { - // N.B. this case overlaps somewhat with - // TyObjectSum, see that fn for details - let mut projection_bounds = Vec::new(); - - let trait_ref = object_path_to_poly_trait_ref(this, - rscope, - trait_def_id, - path, - &mut projection_bounds); - - trait_ref_to_object_type(this, rscope, path.span, - trait_ref, projection_bounds, &[]) - } - def::DefTy(did, _) | def::DefStruct(did) => { - ast_path_to_ty(this, rscope, did, path).ty - } - def::DefTyParam(space, index, _, name) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - ty::mk_param(tcx, space, index, name) - } - def::DefSelfTy(_) => { - // n.b.: resolve guarantees that the this type only appears in a - // trait, which we rely upon in various places when creating - // substs - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - ty::mk_self_type(tcx) - } - def::DefMod(id) => { - span_fatal!(tcx.sess, ast_ty.span, E0247, - "found module name used as a type: {}", - tcx.map.node_to_string(id.node)); - } - def::DefPrimTy(_) => { - panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call"); - } - def::DefAssociatedTy(trait_type_id) => { - let path_str = tcx.map.path_to_string( - tcx.map.get_parent(trait_type_id.node)); - span_err!(tcx.sess, ast_ty.span, E0223, - "ambiguous associated \ - type; specify the type \ - using the syntax `::{}`", - path_str, - &token::get_ident( - path.segments - .last() - .unwrap() - .identifier)); - this.tcx().types.err - } - def::DefAssociatedPath(provenance, assoc_ident) => { - associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name) - } - _ => { - span_fatal!(tcx.sess, ast_ty.span, E0248, - "found value name used \ - as a type: {:?}", - a_def); - } - } - } - ast::TyQPath(ref qpath) => { - qpath_to_ty(this, rscope, ast_ty, &**qpath) - } - ast::TyFixedLengthVec(ref ty, ref e) => { - match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) { - Ok(ref r) => { - match *r { - const_eval::const_int(i) => - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), - Some(i as uint)), - const_eval::const_uint(i) => - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), - Some(i as uint)), - _ => { - span_fatal!(tcx.sess, ast_ty.span, E0249, - "expected constant expr for array length"); - } - } - } - Err(ref r) => { - span_fatal!(tcx.sess, ast_ty.span, E0250, - "expected constant expr for array \ - length: {}", - *r); - } - } - } - ast::TyTypeof(ref _e) => { - tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented"); - } - ast::TyInfer => { - // TyInfer also appears as the type of arguments or return - // values in a ExprClosure, or as - // the type of local variables. Both of these cases are - // handled specially and will not descend into this routine. - this.ty_infer(ast_ty.span) } } - }); + ast::TyPtr(ref mt) => { + ty::mk_ptr(tcx, ty::mt { + ty: ast_ty_to_ty(this, rscope, &*mt.ty), + mutbl: mt.mutbl + }) + } + ast::TyRptr(ref region, ref mt) => { + let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region); + debug!("ty_rptr r={}", r.repr(this.tcx())); + let rscope1 = + &ObjectLifetimeDefaultRscope::new( + rscope, + Some(ty::ObjectLifetimeDefault::Specific(r))); + let t = ast_ty_to_ty(this, rscope1, &*mt.ty); + ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) + } + ast::TyTup(ref fields) => { + let flds = fields.iter() + .map(|t| ast_ty_to_ty(this, rscope, &**t)) + .collect(); + ty::mk_tup(tcx, flds) + } + ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), + ast::TyBareFn(ref bf) => { + if bf.decl.variadic && bf.abi != abi::C { + span_err!(tcx.sess, ast_ty.span, E0222, + "variadic function must have C calling convention"); + } + let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); + ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn)) + } + ast::TyPolyTraitRef(ref bounds) => { + conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds) + } + ast::TyPath(ref maybe_qself, ref path) => { + let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) { + d + } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself { + // Create some fake resolution that can't possibly be a type. + def::PathResolution { + base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)), + last_private: LastMod(AllPublic), + depth: path.segments.len() + } + } else { + tcx.sess.span_bug(ast_ty.span, + &format!("unbound path {}", ast_ty.repr(tcx))) + }; + let mut def = path_res.base_def; + let base_ty_end = path.segments.len() - path_res.depth; + let opt_self_ty = maybe_qself.as_ref().map(|qself| { + ast_ty_to_ty(this, rscope, &qself.ty) + }); + let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span, + PathParamMode::Explicit, &mut def, + opt_self_ty, + &path.segments[..base_ty_end], + &path.segments[base_ty_end..]); + + if path_res.depth != 0 && ty.sty != ty::ty_err { + // Write back the new resolution. + tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution { + base_def: def, + last_private: path_res.last_private, + depth: 0 + }); + } + + ty + } + ast::TyFixedLengthVec(ref ty, ref e) => { + match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) { + Ok(r) => { + match r { + const_eval::const_int(i) => + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), + Some(i as uint)), + const_eval::const_uint(i) => + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), + Some(i as uint)), + _ => { + span_fatal!(tcx.sess, ast_ty.span, E0249, + "expected constant expr for array length"); + } + } + } + Err(r) => { + span_fatal!(tcx.sess, ast_ty.span, E0250, + "expected constant expr for array length: {}", r); + } + } + } + ast::TyTypeof(ref _e) => { + tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented"); + } + ast::TyInfer => { + // TyInfer also appears as the type of arguments or return + // values in a ExprClosure, or as + // the type of local variables. Both of these cases are + // handled specially and will not descend into this routine. + this.ty_infer(ast_ty.span) + } + }; tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ)); return typ; @@ -1803,8 +1896,8 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, for ast_bound in ast_bounds { match *ast_bound { ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { - match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { - def::DefaultImpl(trait_did) => { + match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { + def::DefTrait(trait_did) => { match trait_def_ids.get(&trait_did) { // Already seen this trait. We forbid // duplicates in the list (for some diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 26ba0fe8ed1..dd2ab6c6b13 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -103,7 +103,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, demand::eqtype(fcx, pat.span, expected, lhs_ty); } ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => { - let const_did = tcx.def_map.borrow()[pat.id].clone().def_id(); + let const_did = tcx.def_map.borrow()[pat.id].def_id(); let const_scheme = ty::lookup_item_type(tcx, const_did); assert!(const_scheme.generics.is_empty()); let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, @@ -433,9 +433,9 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - let def = tcx.def_map.borrow()[pat.id].clone(); + let def = tcx.def_map.borrow()[pat.id].full_def(); let (enum_def_id, variant_def_id) = match def { - def::DefaultImpl(_) => { + def::DefTrait(_) => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0168, "use of trait `{}` in a struct pattern", name); @@ -470,7 +470,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, }; instantiate_path(pcx.fcx, - path, + &path.segments, ty::lookup_item_type(tcx, enum_def_id), &ty::lookup_predicates(tcx, enum_def_id), None, @@ -502,7 +502,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - let def = tcx.def_map.borrow()[pat.id].clone(); + let def = tcx.def_map.borrow()[pat.id].full_def(); let enum_def = def.variant_def_ids() .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); @@ -517,7 +517,9 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } else { ctor_scheme }; - instantiate_path(pcx.fcx, path, path_scheme, &ctor_predicates, None, def, pat.span, pat.id); + instantiate_path(pcx.fcx, &path.segments, + path_scheme, &ctor_predicates, + 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/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 256cd415a33..7ef2db2c28d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -14,6 +14,8 @@ use astconv::AstConv; use check::{FnCtxt}; use check::vtable; use check::vtable::select_new_fcx_obligations; +use middle::def; +use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; use middle::traits; use middle::ty::*; @@ -66,7 +68,8 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr_id: ast::NodeId) -> bool { - match probe::probe(fcx, span, method_name, self_ty, call_expr_id) { + let mode = probe::Mode::MethodCall; + match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) { Ok(..) => true, Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, @@ -103,8 +106,9 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr.repr(fcx.tcx()), self_expr.repr(fcx.tcx())); + let mode = probe::Mode::MethodCall; let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); - let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id)); + let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)); Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } @@ -301,6 +305,29 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(callee) } +pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + span: Span, + method_name: ast::Name, + self_ty: Ty<'tcx>, + expr_id: ast::NodeId) + -> Result<(def::Def, LastPrivate), MethodError> +{ + let mode = probe::Mode::Path; + let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id)); + let def_id = pick.method_ty.def_id; + let mut lp = LastMod(AllPublic); + let provenance = match pick.kind { + probe::InherentImplPick(impl_def_id) => { + if pick.method_ty.vis != ast::Public { + lp = LastMod(DependsOn(def_id)); + } + def::FromImpl(impl_def_id) + } + _ => def::FromTrait(pick.method_ty.container.id()) + }; + Ok((def::DefMethod(def_id, provenance), lp)) +} + /// Find method with name `method_name` defined in `trait_def_id` and return it, along with its /// index (or `None`, if no such method). diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 1cc4fe37fbd..f24da78bc7d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -37,6 +37,7 @@ pub use self::PickKind::*; struct ProbeContext<'a, 'tcx:'a> { fcx: &'a FnCtxt<'a, 'tcx>, span: Span, + mode: Mode, method_name: ast::Name, steps: Rc>>, opt_simplified_steps: Option>, @@ -108,17 +109,30 @@ pub enum PickAdjustment { AutoRef(ast::Mutability, Box), } +#[derive(PartialEq, Eq, Copy)] +pub enum Mode { + // An expression of the form `receiver.method_name(...)`. + // Autoderefs are performed on `receiver`, lookup is done based on the + // `self` argument of the method, and static methods aren't considered. + MethodCall, + // An expression of the form `Type::method` or `::method`. + // No autoderefs are performed, lookup is done based on the type each + // implementation is for, and static methods are included. + Path +} + pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, + mode: Mode, method_name: ast::Name, self_ty: Ty<'tcx>, - call_expr_id: ast::NodeId) + scope_expr_id: ast::NodeId) -> PickResult<'tcx> { - debug!("probe(self_ty={}, method_name={}, call_expr_id={})", + debug!("probe(self_ty={}, method_name={}, scope_expr_id={})", self_ty.repr(fcx.tcx()), method_name, - call_expr_id); + scope_expr_id); // FIXME(#18741) -- right now, creating the steps involves evaluating the // `*` operator, which registers obligations that then escape into @@ -127,9 +141,16 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // it ride, although it's really not great, and in fact could I // think cause spurious errors. Really though this part should // take place in the `fcx.infcx().probe` below. - let steps = match create_steps(fcx, span, self_ty) { - Some(steps) => steps, - None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())), + let steps = if mode == Mode::MethodCall { + match create_steps(fcx, span, self_ty) { + Some(steps) => steps, + None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())), + } + } else { + vec![CandidateStep { + self_ty: self_ty, + adjustment: AutoDeref(0) + }] }; // Create a list of simplified self types, if we can. @@ -153,12 +174,15 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later - let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures fcx.infcx().probe(|_| { - let (steps, opt_simplified_steps) = dummy.take().unwrap(); - let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps); + let mut probe_cx = ProbeContext::new(fcx, + span, + mode, + method_name, + steps, + opt_simplified_steps); probe_cx.assemble_inherent_candidates(); - try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id)); + try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)); probe_cx.pick() }) } @@ -198,6 +222,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, impl<'a,'tcx> ProbeContext<'a,'tcx> { fn new(fcx: &'a FnCtxt<'a,'tcx>, span: Span, + mode: Mode, method_name: ast::Name, steps: Vec>, opt_simplified_steps: Option>) @@ -206,6 +231,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ProbeContext { fcx: fcx, span: span, + mode: mode, method_name: method_name, inherent_candidates: Vec::new(), extension_candidates: Vec::new(), @@ -255,6 +281,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ty::ty_closure(did, _, _) => { self.assemble_inherent_impl_candidates_for_type(did); } + ty::ty_uniq(_) => { + if let Some(box_did) = self.tcx().lang_items.owned_box() { + self.assemble_inherent_impl_candidates_for_type(box_did); + } + } ty::ty_param(p) => { self.assemble_inherent_candidates_from_param(self_ty, p); } @@ -292,11 +323,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { return self.record_static_candidate(ImplSource(impl_def_id)); } - let impl_substs = self.impl_substs(impl_def_id); + let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); + let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty); // Determine the receiver type that the method itself expects. let xform_self_ty = - self.xform_self_ty(&method, &impl_substs); + self.xform_self_ty(&method, impl_ty, &impl_substs); self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -330,7 +362,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { new_trait_ref.def_id, method_num); - let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs); + let xform_self_ty = this.xform_self_ty(&m, + new_trait_ref.self_ty(), + new_trait_ref.substs); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -373,7 +407,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.erase_late_bound_regions(&poly_trait_ref); let xform_self_ty = - this.xform_self_ty(&m, trait_ref.substs); + this.xform_self_ty(&m, + trait_ref.self_ty(), + trait_ref.substs); debug!("found match: trait_ref={} substs={} m={}", trait_ref.repr(this.tcx()), @@ -540,7 +576,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { continue; } - let impl_substs = self.impl_substs(impl_def_id); + let (_, impl_substs) = self.impl_ty_and_substs(impl_def_id); debug!("impl_substs={}", impl_substs.repr(self.tcx())); @@ -553,7 +589,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Determine the receiver type that the method itself expects. let xform_self_ty = - self.xform_self_ty(&method, impl_trait_ref.substs); + self.xform_self_ty(&method, + impl_trait_ref.self_ty(), + impl_trait_ref.substs); debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx())); @@ -630,7 +668,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { &trait_def.generics, step.self_ty); - let xform_self_ty = self.xform_self_ty(&method_ty, &substs); + let xform_self_ty = self.xform_self_ty(&method_ty, + step.self_ty, + &substs); self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, method_ty: method_ty.clone(), @@ -684,7 +724,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { bound.repr(self.tcx())); if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() { - let xform_self_ty = self.xform_self_ty(&method, bound.substs); + let xform_self_ty = self.xform_self_ty(&method, + bound.self_ty(), + bound.substs); debug!("assemble_projection_candidates: bound={} xform_self_ty={}", bound.repr(self.tcx()), @@ -714,7 +756,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { .filter(|b| b.def_id() == trait_def_id) { let bound = self.erase_late_bound_regions(&poly_bound); - let xform_self_ty = self.xform_self_ty(&method_ty, bound.substs); + let xform_self_ty = self.xform_self_ty(&method_ty, + bound.self_ty(), + bound.substs); debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}", bound.repr(self.tcx()), @@ -1023,7 +1067,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // "fast track" -- check for usage of sugar match method.explicit_self { ty::StaticExplicitSelfCategory => { - // fallthrough + if self.mode == Mode::Path { + return true; + } } ty::ByValueExplicitSelfCategory | ty::ByReferenceExplicitSelfCategory(..) | @@ -1047,11 +1093,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn xform_self_ty(&self, method: &Rc>, + impl_ty: Ty<'tcx>, substs: &subst::Substs<'tcx>) -> Ty<'tcx> { - debug!("xform_self_ty(self_ty={}, substs={})", - method.fty.sig.0.inputs[0].repr(self.tcx()), + debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})", + impl_ty.repr(self.tcx()), + method.fty.sig.0.inputs.get(0).repr(self.tcx()), substs.repr(self.tcx())); assert!(!substs.has_escaping_regions()); @@ -1063,6 +1111,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // if there are any. assert_eq!(substs.types.len(subst::FnSpace), 0); assert_eq!(substs.regions().len(subst::FnSpace), 0); + + if self.mode == Mode::Path { + return impl_ty; + } + let placeholder; let mut substs = substs; if @@ -1094,9 +1147,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { xform_self_ty } - fn impl_substs(&self, - impl_def_id: ast::DefId) - -> subst::Substs<'tcx> + /// Get the type of an impl and generate substitutions with placeholders. + fn impl_ty_and_substs(&self, + impl_def_id: ast::DefId) + -> (Ty<'tcx>, subst::Substs<'tcx>) { let impl_pty = ty::lookup_item_type(self.tcx(), impl_def_id); @@ -1108,7 +1162,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { impl_pty.generics.regions.map( |_| ty::ReStatic); // see erase_late_bound_regions() for an expl of why 'static - subst::Substs::new(type_vars, region_placeholders) + let substs = subst::Substs::new(type_vars, region_placeholders); + (impl_pty.ty, substs) } /// Replace late-bound-regions bound by `value` with `'static` using diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 9b1693cba1e..9832fe1cb6e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -33,7 +33,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, method_name: ast::Name, - callee_expr: &ast::Expr, + rcvr_expr: Option<&ast::Expr>, error: MethodError) { // avoid suggestions when we don't know what's going on. @@ -46,16 +46,6 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let cx = fcx.tcx(); let method_ustring = method_name.user_string(cx); - // True if the type is a struct and contains a field with - // the same name as the not-found method - let is_field = match rcvr_ty.sty { - ty::ty_struct(did, _) => - ty::lookup_struct_fields(cx, did) - .iter() - .any(|f| f.name.user_string(cx) == method_ustring), - _ => false - }; - fcx.type_error_message( span, |actual| { @@ -68,10 +58,13 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None); // If the method has the name of a field, give a help note - if is_field { - cx.sess.span_note(span, - &format!("use `(s.{0})(...)` if you meant to call the \ - function stored in the `{0}` field", method_ustring)); + if let (&ty::ty_struct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { + let fields = ty::lookup_struct_fields(cx, did); + if fields.iter().any(|f| f.name == method_name) { + cx.sess.span_note(span, + &format!("use `(s.{0})(...)` if you meant to call the \ + function stored in the `{0}` field", method_ustring)); + } } if static_sources.len() > 0 { @@ -82,7 +75,8 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, report_candidates(fcx, span, method_name, static_sources); } - suggest_traits_to_import(fcx, span, rcvr_ty, method_name, out_of_scope_traits) + suggest_traits_to_import(fcx, span, rcvr_ty, method_name, + rcvr_expr, out_of_scope_traits) } MethodError::Ambiguity(sources) => { @@ -93,15 +87,18 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } MethodError::ClosureAmbiguity(trait_def_id) => { - fcx.sess().span_err( - span, - &*format!("the `{}` method from the `{}` trait cannot be explicitly \ - invoked on this closure as we have not yet inferred what \ - kind of closure it is; use overloaded call notation instead \ - (e.g., `{}()`)", - method_name.user_string(fcx.tcx()), - ty::item_path_str(fcx.tcx(), trait_def_id), - pprust::expr_to_string(callee_expr))); + let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ + invoked on this closure as we have not yet inferred what \ + kind of closure it is", + method_name.user_string(fcx.tcx()), + ty::item_path_str(fcx.tcx(), trait_def_id)); + let msg = if let Some(callee) = rcvr_expr { + format!("{}; use overloaded call notation instead (e.g., `{}()`)", + msg, pprust::expr_to_string(callee)) + } else { + msg + }; + fcx.sess().span_err(span, &msg); } } @@ -156,6 +153,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, method_name: ast::Name, + rcvr_expr: Option<&ast::Expr>, valid_out_of_scope_traits: Vec) { let tcx = fcx.tcx(); @@ -184,7 +182,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return } - let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty); + let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr); // there's no implemented traits, so lets suggest some traits to // implement, by finding ones that have the method name, and are @@ -233,33 +231,39 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// autoderefs of `rcvr_ty`. fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, - rcvr_ty: Ty<'tcx>) -> bool { - check::autoderef(fcx, span, rcvr_ty, None, - check::UnresolvedTypeAction::Ignore, check::NoPreference, - |&: ty, _| { - let is_local = match ty.sty { + rcvr_ty: Ty<'tcx>, + rcvr_expr: Option<&ast::Expr>) -> bool { + fn is_local(ty: Ty) -> bool { + match ty.sty { ty::ty_enum(did, _) | ty::ty_struct(did, _) => ast_util::is_local(did), ty::ty_trait(ref tr) => ast_util::is_local(tr.principal_def_id()), ty::ty_param(_) => true, - // the user cannot implement traits for unboxed closures, so - // there's no point suggesting anything at all, local or not. - ty::ty_closure(..) => return Some(false), - // everything else (primitive types etc.) is effectively // non-local (there are "edge" cases, e.g. (LocalType,), but // the noise from these sort of types is usually just really // annoying, rather than any sort of help). _ => false - }; - if is_local { - Some(true) + } + } + + // This occurs for UFCS desugaring of `T::method`, where there is no + // receiver expression for the method call, and thus no autoderef. + if rcvr_expr.is_none() { + return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty)); + } + + check::autoderef(fcx, span, rcvr_ty, None, + check::UnresolvedTypeAction::Ignore, check::NoPreference, + |ty, _| { + if is_local(ty) { + Some(()) } else { None } - }).2.unwrap_or(false) + }).2.is_some() } #[derive(Copy)] @@ -330,7 +334,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { cstore: &cstore::CStore, dl: decoder::DefLike) { match dl { - decoder::DlDef(def::DefaultImpl(did)) => { + decoder::DlDef(def::DefTrait(did)) => { traits.push(TraitInfo::new(did)); } decoder::DlDef(def::DefMod(did)) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 81e72ef6326..d7a11b8a515 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -82,14 +82,16 @@ pub use self::compare_method::compare_impl_method; use self::IsBinopAssignment::*; use self::TupleArgumentsFlag::*; -use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv}; +use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; +use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::{const_eval, def}; use middle::infer; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::pat_util::{self, pat_id_map}; +use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::traits; @@ -101,7 +103,7 @@ use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; use middle::ty_fold::{TypeFolder, TypeFoldable}; use rscope::RegionScope; use session::Session; -use {CrateCtxt, lookup_def_ccx, require_same_types}; +use {CrateCtxt, lookup_full_def, require_same_types}; use TypeAndSubsts; use lint; use util::common::{block_query, indenter, loop_query}; @@ -1598,23 +1600,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::TypeScheme { generics, ty: decl_ty } = ty::lookup_item_type(tcx, did); - let wants_params = - generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace); - - let needs_defaults = - wants_params && - path.segments.iter().all(|s| s.parameters.is_empty()); - - let substs = if needs_defaults { - let tps = - self.infcx().next_ty_vars(generics.types.len(TypeSpace)); - let rps = - self.infcx().region_vars_for_defs(path.span, - generics.regions.get_slice(TypeSpace)); - Substs::new_type(tps, rps) - } else { - astconv::ast_path_substs_for_ty(self, self, &generics, path) - }; + let substs = astconv::ast_path_substs_for_ty(self, self, + path.span, + PathParamMode::Optional, + &generics, + path.segments.last().unwrap()); let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty); @@ -2698,7 +2688,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } Err(error) => { method::report_error(fcx, method_name.span, expr_t, - method_name.node.name, rcvr, error); + method_name.node.name, Some(rcvr), error); fcx.write_error(expr.id); fcx.tcx().types.err } @@ -3408,10 +3398,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let mut checked = false; opt_place.as_ref().map(|place| match place.node { - ast::ExprPath(ref path) => { + ast::ExprPath(None, ref path) => { // FIXME(pcwalton): For now we hardcode the two permissible // places: the exchange heap and the managed heap. - let definition = lookup_def(fcx, path.span, place.id); + let definition = lookup_full_def(tcx, path.span, place.id); let def_id = definition.def_id(); let referent_ty = fcx.expr_ty(&**subexpr); if tcx.lang_items.exchange_heap() == Some(def_id) { @@ -3601,26 +3591,65 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; fcx.write_ty(id, oprnd_t); } - ast::ExprPath(ref path) => { - let defn = lookup_def(fcx, path.span, id); - let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn); - instantiate_path(fcx, path, scheme, &predicates, None, defn, expr.span, expr.id); + ast::ExprPath(ref maybe_qself, ref path) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| { + fcx.to_ty(&qself.ty) + }); - // 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 path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) { + d + } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself { + // Create some fake resolution that can't possibly be a type. + def::PathResolution { + base_def: def::DefMod(local_def(ast::CRATE_NODE_ID)), + last_private: LastMod(AllPublic), + depth: path.segments.len() + } + } else { + tcx.sess.span_bug(expr.span, + &format!("unbound path {}", expr.repr(tcx))[]) + }; - let defn = lookup_def(fcx, expr.span, id); - let (scheme, predicates) = type_scheme_and_predicates_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, scheme, &predicates, Some(self_ty), - defn, expr.span, expr.id); + let mut def = path_res.base_def; + if path_res.depth == 0 { + let (scheme, predicates) = + type_scheme_and_predicates_for_def(fcx, expr.span, def); + instantiate_path(fcx, &path.segments, + scheme, &predicates, + opt_self_ty, def, expr.span, id); + } else { + let ty_segments = path.segments.init(); + let base_ty_end = path.segments.len() - path_res.depth; + let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, expr.span, + PathParamMode::Optional, + &mut def, + opt_self_ty, + &ty_segments[..base_ty_end], + &ty_segments[base_ty_end..]); + let method_segment = path.segments.last().unwrap(); + let method_name = method_segment.identifier.name; + match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) { + Ok((def, lp)) => { + // Write back the new resolution. + tcx.def_map.borrow_mut().insert(id, def::PathResolution { + base_def: def, + last_private: path_res.last_private.or(lp), + depth: 0 + }); + + let (scheme, predicates) = + type_scheme_and_predicates_for_def(fcx, expr.span, def); + instantiate_path(fcx, slice::ref_slice(method_segment), + scheme, &predicates, + Some(ty), def, expr.span, id); + } + Err(error) => { + method::report_error(fcx, expr.span, ty, + method_name, None, error); + fcx.write_error(id); + } + } + } // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. @@ -3855,14 +3884,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprStruct(ref path, ref fields, ref base_expr) => { // Resolve the path. - let def = tcx.def_map.borrow().get(&id).cloned(); + let def = lookup_full_def(tcx, path.span, id); let struct_id = match def { - Some(def::DefVariant(enum_id, variant_id, true)) => { + def::DefVariant(enum_id, variant_id, true) => { check_struct_enum_variant(fcx, id, expr.span, enum_id, variant_id, &fields[..]); enum_id } - Some(def::DefaultImpl(def_id)) => { + def::DefTrait(def_id) => { span_err!(tcx.sess, path.span, E0159, "use of trait `{}` as a struct constructor", pprust::path_to_string(path)); @@ -3872,7 +3901,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, base_expr); def_id }, - Some(def) => { + def => { // Verify that this was actually a struct. let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id()); match typ.ty.sty { @@ -3897,10 +3926,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, def.def_id() } - _ => { - tcx.sess.span_bug(path.span, - "structure constructor wasn't resolved") - } }; // Turn the path into a type and verify that that type unifies with @@ -4614,10 +4639,6 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, check_instantiable(ccx.tcx, sp, id); } -pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> def::Def { - lookup_def_ccx(fcx.ccx, sp, id) -} - // Returns the type parameter count and the type for the given definition. fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, @@ -4629,22 +4650,20 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, ty::GenericPredicates::empty()) } - def::DefFn(id, _) | def::DefStaticMethod(id, _) | def::DefMethod(id, _, _) | + def::DefFn(id, _) | def::DefMethod(id, _) | def::DefStatic(id, _) | def::DefVariant(_, id, _) | def::DefStruct(id) | def::DefConst(id) => { (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id)) } - def::DefaultImpl(_) | + def::DefTrait(_) | def::DefTy(..) | def::DefAssociatedTy(..) | - def::DefAssociatedPath(..) | def::DefPrimTy(_) | def::DefTyParam(..) | def::DefMod(..) | def::DefForeignMod(..) | def::DefUse(..) | def::DefRegion(..) | - def::DefTyParamBinder(..) | def::DefLabel(..) | def::DefSelfTy(..) => { fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn)); @@ -4655,15 +4674,15 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - path: &ast::Path, + segments: &[ast::PathSegment], type_scheme: TypeScheme<'tcx>, type_predicates: &ty::GenericPredicates<'tcx>, opt_self_ty: Option>, def: def::Def, span: Span, node_id: ast::NodeId) { - debug!("instantiate_path(path={}, def={}, node_id={}, type_scheme={})", - path.repr(fcx.tcx()), + debug!("instantiate_path(path={:?}, def={}, node_id={}, type_scheme={})", + segments, def.repr(fcx.tcx()), node_id, type_scheme.repr(fcx.tcx())); @@ -4727,23 +4746,23 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // // The first step then is to categorize the segments appropriately. - assert!(path.segments.len() >= 1); + assert!(segments.len() >= 1); + + let mut ufcs_method = None; let mut segment_spaces: Vec<_>; match def { // Case 1 and 1b. Reference to a *type* or *enum variant*. def::DefSelfTy(..) | def::DefStruct(..) | def::DefVariant(..) | - def::DefTyParamBinder(..) | def::DefTy(..) | def::DefAssociatedTy(..) | - def::DefAssociatedPath(..) | - def::DefaultImpl(..) | + def::DefTrait(..) | def::DefPrimTy(..) | def::DefTyParam(..) => { // Everything but the final segment should have no // parameters at all. - segment_spaces = repeat(None).take(path.segments.len() - 1).collect(); + segment_spaces = repeat(None).take(segments.len() - 1).collect(); segment_spaces.push(Some(subst::TypeSpace)); } @@ -4751,25 +4770,29 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefFn(..) | def::DefConst(..) | def::DefStatic(..) => { - segment_spaces = repeat(None).take(path.segments.len() - 1).collect(); + segment_spaces = repeat(None).take(segments.len() - 1).collect(); segment_spaces.push(Some(subst::FnSpace)); } // Case 3. Reference to a method. - def::DefStaticMethod(_, providence) | - def::DefMethod(_, _, providence) => { - assert!(path.segments.len() >= 2); - - match providence { + def::DefMethod(_, provenance) => { + match provenance { def::FromTrait(trait_did) => { callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did) } def::FromImpl(_) => {} } - segment_spaces = repeat(None).take(path.segments.len() - 2).collect(); - segment_spaces.push(Some(subst::TypeSpace)); - segment_spaces.push(Some(subst::FnSpace)); + if segments.len() >= 2 { + segment_spaces = repeat(None).take(segments.len() - 2).collect(); + segment_spaces.push(Some(subst::TypeSpace)); + segment_spaces.push(Some(subst::FnSpace)); + } else { + // `::method` will end up here, and so can `T::method`. + let self_ty = opt_self_ty.expect("UFCS sugared method missing Self"); + segment_spaces = vec![Some(subst::FnSpace)]; + ufcs_method = Some((provenance, self_ty)); + } } // Other cases. Various nonsense that really shouldn't show up @@ -4782,10 +4805,15 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefRegion(..) | def::DefLabel(..) | def::DefUpvar(..) => { - segment_spaces = repeat(None).take(path.segments.len()).collect(); + segment_spaces = repeat(None).take(segments.len()).collect(); } } - assert_eq!(segment_spaces.len(), path.segments.len()); + assert_eq!(segment_spaces.len(), segments.len()); + + // In `>::method`, `A` and `B` are mandatory, but + // `opt_self_ty` can also be Some for `Foo::method`, where Foo's + // type parameters are not mandatory. + let require_type_space = opt_self_ty.is_some() && ufcs_method.is_none(); debug!("segment_spaces={:?}", segment_spaces); @@ -4799,16 +4827,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // provided (if any) into their appropriate spaces. We'll also report // errors if type parameters are provided in an inappropriate place. let mut substs = Substs::empty(); - for (opt_space, segment) in segment_spaces.iter().zip(path.segments.iter()) { + for (opt_space, segment) in segment_spaces.iter().zip(segments.iter()) { match *opt_space { None => { - report_error_if_segment_contains_type_parameters(fcx, segment); + check_path_args(fcx.tcx(), slice::ref_slice(segment), + NO_TPS | NO_REGIONS); } Some(space) => { push_explicit_parameters_from_segment_to_substs(fcx, space, - path.span, + span, type_defs, region_defs, segment, @@ -4817,9 +4846,9 @@ 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); + if type_defs.len(subst::SelfSpace) == 1 { + substs.types.push(subst::SelfSpace, self_ty); + } } // Now we have to compare the types that the user *actually* @@ -4829,7 +4858,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // to add defaults. If the user provided *too many* types, that's // a problem. for &space in &ParamSpace::all() { - adjust_type_parameters(fcx, span, space, type_defs, &mut substs); + adjust_type_parameters(fcx, span, space, type_defs, + require_type_space, &mut substs); assert_eq!(substs.types.len(space), type_defs.len(space)); adjust_region_parameters(fcx, span, space, region_defs, &mut substs); @@ -4852,27 +4882,32 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // the referenced item. let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty); + + if let Some((def::FromImpl(impl_def_id), self_ty)) = ufcs_method { + // In the case of `Foo::method` and `>::method`, if `method` + // is inherent, there is no `Self` parameter, instead, the impl needs + // type parameters, which we can infer by unifying the provided `Self` + // with the substituted impl type. + let impl_scheme = ty::lookup_item_type(fcx.tcx(), impl_def_id); + assert_eq!(substs.types.len(subst::TypeSpace), + impl_scheme.generics.types.len(subst::TypeSpace)); + assert_eq!(substs.regions().len(subst::TypeSpace), + impl_scheme.generics.regions.len(subst::TypeSpace)); + + let impl_ty = fcx.instantiate_type_scheme(span, &substs, &impl_scheme.ty); + if fcx.mk_subty(false, infer::Misc(span), self_ty, impl_ty).is_err() { + fcx.tcx().sess.span_bug(span, + &format!( + "instantiate_path: (UFCS) {} was a subtype of {} but now is not?", + self_ty.repr(fcx.tcx()), + impl_ty.repr(fcx.tcx()))); + } + } + fcx.write_ty(node_id, ty_substituted); fcx.write_substs(node_id, ty::ItemSubsts { substs: substs }); return; - fn report_error_if_segment_contains_type_parameters( - fcx: &FnCtxt, - segment: &ast::PathSegment) - { - for typ in &segment.parameters.types() { - span_err!(fcx.tcx().sess, typ.span, E0085, - "type parameters may not appear here"); - break; - } - - for lifetime in &segment.parameters.lifetimes() { - span_err!(fcx.tcx().sess, lifetime.span, E0086, - "lifetime parameters may not appear here"); - break; - } - } - /// Finds the parameters that the user provided and adds them to `substs`. If too many /// parameters are provided, then reports an error and clears the output vector. /// @@ -5007,6 +5042,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, space: ParamSpace, defs: &VecPerParamSpace>, + require_type_space: bool, substs: &mut Substs<'tcx>) { let provided_len = substs.types.len(space); @@ -5029,9 +5065,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Nothing specified at all: supply inference variables for // everything. - if provided_len == 0 { - substs.types.replace(space, - fcx.infcx().next_ty_vars(desired.len())); + if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { + substs.types.replace(space, fcx.infcx().next_ty_vars(desired.len())); return; } @@ -5153,18 +5188,15 @@ pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool { _ => false } })) || - // Second: is there a labeled break with label - // nested anywhere inside the loop? + // Second: is there a labeled break with label + // nested anywhere inside the loop? (block_query(b, |e| { - match e.node { - ast::ExprBreak(Some(_)) => { - match cx.def_map.borrow().get(&e.id) { - Some(&def::DefLabel(loop_id)) if id == loop_id => true, - _ => false, - } - } - _ => false - }})) + if let ast::ExprBreak(Some(_)) = e.node { + lookup_full_def(cx, e.span, e.id) == def::DefLabel(id) + } else { + false + } + })) } pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 399795c6656..e024526d001 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -81,8 +81,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => { self.check_impl(item); } - ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => { - let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id); + ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => { + let trait_ref = ty::impl_id_to_trait_ref(ccx.tcx, item.id); ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id); match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { Some(ty::BoundSend) | Some(ty::BoundSync) => {} diff --git a/src/librustc_typeck/coherence/impls.rs b/src/librustc_typeck/coherence/impls.rs index e535b86a7bf..e89c96b36e1 100644 --- a/src/librustc_typeck/coherence/impls.rs +++ b/src/librustc_typeck/coherence/impls.rs @@ -28,8 +28,8 @@ struct ImplsChecker<'cx, 'tcx:'cx> { impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v ast::Item) { match item.node { - ast::ItemImpl(_, _, _, Some(ref opt_trait), _, _) => { - let trait_ref = ty::node_id_to_trait_ref(self.tcx, opt_trait.ref_id); + ast::ItemImpl(_, _, _, Some(_), _, _) => { + let trait_ref = ty::impl_id_to_trait_ref(self.tcx, item.id); if let Some(_) = self.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { match trait_ref.self_ty().sty { ty::ty_struct(..) | ty::ty_enum(..) => {} diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 7dac1eeb6f1..1913b55f1d8 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -106,19 +106,9 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> { //debug!("(checking coherence) item '{}'", token::get_ident(item.ident)); - match item.node { - ItemImpl(_, _, _, ref opt_trait, _, _) => { - match opt_trait.clone() { - Some(opt_trait) => { - self.cc.check_implementation(item, &[opt_trait]); - } - None => self.cc.check_implementation(item, &[]) - } - } - _ => { - // Nothing to do. - } - }; + if let ItemImpl(_, _, _, ref opt_trait, _, _) = item.node { + self.cc.check_implementation(item, opt_trait.as_ref()) + } visit::walk_item(self, item); } @@ -155,9 +145,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { self.check_implementations_of_copy(); } - fn check_implementation(&self, - item: &Item, - associated_traits: &[TraitRef]) { + fn check_implementation(&self, item: &Item, opt_trait: Option<&TraitRef>) { let tcx = self.crate_context.tcx; let impl_did = local_def(item.id); let self_type = ty::lookup_item_type(tcx, impl_did); @@ -167,9 +155,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let impl_items = self.create_impl_from_item(item); - for associated_trait in associated_traits { - let trait_ref = ty::node_id_to_trait_ref(self.crate_context.tcx, - associated_trait.ref_id); + if opt_trait.is_some() { + let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, item.id); debug!("(checking implementation) adding impl for trait '{}', item '{}'", trait_ref.repr(self.crate_context.tcx), token::get_ident(item.ident)); @@ -191,7 +178,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } Some(base_type_def_id) => { // FIXME: Gather up default methods? - if associated_traits.len() == 0 { + if opt_trait.is_none() { self.add_inherent_impl(base_type_def_id, impl_did); } } @@ -289,7 +276,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // Converts an implementation in the AST to a vector of items. fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { - ItemImpl(_, _, _, ref trait_refs, _, ref ast_items) => { + ItemImpl(_, _, _, ref opt_trait, _, ref ast_items) => { let mut items: Vec = ast_items.iter() .map(|ast_item| { @@ -304,13 +291,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }).collect(); - if let Some(ref trait_ref) = *trait_refs { - let ty_trait_ref = ty::node_id_to_trait_ref( - self.crate_context.tcx, - trait_ref.ref_id); + if opt_trait.is_some() { + let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, + item.id); self.instantiate_default_methods(local_def(item.id), - &*ty_trait_ref, + &*trait_ref, &mut items); } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index d34a16a924f..95dafccd866 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -16,7 +16,6 @@ use middle::ty; use syntax::ast::{Item, ItemImpl}; use syntax::ast; use syntax::ast_util; -use syntax::codemap::Span; use syntax::visit; use util::ppaux::{Repr, UserString}; @@ -30,9 +29,9 @@ struct OrphanChecker<'cx, 'tcx:'cx> { } impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { - fn check_def_id(&self, span: Span, def_id: ast::DefId) { + fn check_def_id(&self, item: &ast::Item, def_id: ast::DefId) { if def_id.krate != ast::LOCAL_CRATE { - span_err!(self.tcx.sess, span, E0116, + span_err!(self.tcx.sess, item.span, E0116, "cannot associate methods with a type outside the \ crate the type is defined in; define and implement \ a trait or new type instead"); @@ -41,7 +40,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { - fn visit_item(&mut self, item: &'v ast::Item) { + fn visit_item(&mut self, item: &ast::Item) { let def_id = ast_util::local_def(item.id); match item.node { ast::ItemImpl(_, _, _, None, _, _) => { @@ -52,15 +51,13 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { match self_ty.sty { ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => { - self.check_def_id(item.span, def_id); + self.check_def_id(item, def_id); } ty::ty_trait(ref data) => { - self.check_def_id(item.span, data.principal_def_id()); + self.check_def_id(item, data.principal_def_id()); } ty::ty_uniq(..) => { - self.check_def_id(item.span, - self.tcx.lang_items.owned_box() - .unwrap()); + self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap()); } _ => { span_err!(self.tcx.sess, item.span, E0118, @@ -96,10 +93,10 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { } } } - ast::ItemDefaultImpl(_, ref ast_trait_ref) => { + ast::ItemDefaultImpl(..) => { // "Trait" impl debug!("coherence2::orphan check: default trait impl {}", item.repr(self.tcx)); - let trait_ref = ty::node_id_to_trait_ref(self.tcx, ast_trait_ref.ref_id); + let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap(); if trait_ref.def_id.krate != ast::LOCAL_CRATE { span_err!(self.tcx.sess, item.span, E0318, "cannot create default implementations for traits outside the \ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 353e8e097a8..bc0c61ad7ad 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -649,8 +649,12 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { &enum_definition.variants); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { - let trait_ref = astconv::instantiate_trait_ref(ccx, &ExplicitRscope, - ast_trait_ref, None, None); + let trait_ref = astconv::instantiate_trait_ref(ccx, + &ExplicitRscope, + ast_trait_ref, + Some(it.id), + None, + None); ty::record_default_trait_implementation(tcx, trait_ref.def_id, local_def(it.id)) } @@ -741,6 +745,7 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { astconv::instantiate_trait_ref(ccx, &ExplicitRscope, trait_ref, + Some(it.id), Some(selfty), None); } @@ -1682,20 +1687,15 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, index: u32) -> bool { - match ast_ty.node { - ast::TyPath(_, id) => { - match ccx.tcx.def_map.borrow()[id] { - def::DefTyParam(s, i, _, _) => { - space == s && index == i - } - _ => { - false - } - } - } - _ => { + if let ast::TyPath(None, _) = ast_ty.node { + let path_res = ccx.tcx.def_map.borrow()[ast_ty.id]; + if let def::DefTyParam(s, i, _, _) = path_res.base_def { + path_res.depth == 0 && space == s && index == i + } else { false } + } else { + false } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6f363faef60..7b43a9fef06 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -80,6 +80,7 @@ register_diagnostics! { E0120, E0121, E0122, + E0123, E0124, E0127, E0128, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 78f13b37a82..78dd66c8e7d 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -163,20 +163,16 @@ fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, tcx.item_substs.borrow_mut().insert(node_id, item_substs); } } -fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def { + +fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def { match tcx.def_map.borrow().get(&id) { - Some(x) => x.clone(), - _ => { + Some(x) => x.full_def(), + None => { span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition") } } } -fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) - -> def::Def { - lookup_def_tcx(ccx.tcx, sp, id) -} - fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, t1_is_expected: bool, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4cd6f6551d0..24b9d03400c 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -46,7 +46,7 @@ pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option) None => return None, }; let def = match tcx.def_map.borrow().get(&id) { - Some(def) => *def, + Some(d) => d.full_def(), None => return None, }; let did = def.def_id(); @@ -69,7 +69,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt, let mut ret = Vec::new(); let did = def.def_id(); let inner = match def { - def::DefaultImpl(did) => { + def::DefTrait(did) => { record_extern_fqn(cx, did, clean::TypeTrait); clean::TraitItem(build_external_trait(cx, tcx, did)) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a3e0cecdd48..b88620d577f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1344,8 +1344,6 @@ pub enum Type { typarams: Option>, did: ast::DefId, }, - // I have no idea how to usefully use this. - TyParamBinder(ast::NodeId), /// For parameterized types, so the consumer of the JSON don't go /// looking for types which don't exist anywhere. Generic(String), @@ -1496,8 +1494,17 @@ impl Clean for ast::Ty { TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx), e.span.to_src(cx)), TyTup(ref tys) => Tuple(tys.clean(cx)), - TyPath(ref p, id) => { - resolve_type(cx, p.clean(cx), id) + TyPath(None, ref p) => { + resolve_type(cx, p.clean(cx), self.id) + } + TyPath(Some(ref qself), ref p) => { + let mut trait_path = p.clone(); + trait_path.segments.pop(); + Type::QPath { + name: p.segments.last().unwrap().identifier.clean(cx), + self_type: box qself.ty.clean(cx), + trait_: box resolve_type(cx, trait_path.clean(cx), self.id) + } } TyObjectSum(ref lhs, ref bounds) => { let lhs_ty = lhs.clean(cx); @@ -1512,7 +1519,6 @@ impl Clean for ast::Ty { } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyParen(ref ty) => ty.clean(cx), - TyQPath(ref qp) => qp.clean(cx), TyPolyTraitRef(ref bounds) => { PolyTraitRef(bounds.clean(cx)) }, @@ -1624,16 +1630,6 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } } -impl Clean for ast::QPath { - fn clean(&self, cx: &DocContext) -> Type { - Type::QPath { - name: self.item_path.identifier.clean(cx), - self_type: box self.self_type.clean(cx), - trait_: box self.trait_ref.clean(cx) - } - } -} - #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum StructField { HiddenStructField, // inserted later by strip passes @@ -2392,7 +2388,7 @@ fn resolve_type(cx: &DocContext, }; debug!("searching for {} in defmap", id); let def = match tcx.def_map.borrow().get(&id) { - Some(&k) => k, + Some(k) => k.full_def(), None => panic!("unresolved id not in defmap") }; @@ -2418,7 +2414,6 @@ fn resolve_type(cx: &DocContext, ast::TyFloat(ast::TyF64) => return Primitive(F64), }, def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()), - def::DefTyParamBinder(i) => return TyParamBinder(i), _ => {} }; let did = register_def(&*cx, def); @@ -2430,7 +2425,7 @@ fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId { def::DefFn(i, _) => (i, TypeFunction), def::DefTy(i, false) => (i, TypeTypedef), def::DefTy(i, true) => (i, TypeEnum), - def::DefaultImpl(i) => (i, TypeTrait), + def::DefTrait(i) => (i, TypeTrait), def::DefStruct(i) => (i, TypeStruct), def::DefMod(i) => (i, TypeModule), def::DefStatic(i, _) => (i, TypeStatic), @@ -2459,7 +2454,7 @@ fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSou fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option { cx.tcx_opt().and_then(|tcx| { - tcx.def_map.borrow().get(&id).map(|&def| register_def(cx, def)) + tcx.def_map.borrow().get(&id).map(|d| register_def(cx, d.full_def())) }) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 11d9ecac14d..03a2d708ee4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -454,9 +454,6 @@ fn tybounds(w: &mut fmt::Formatter, impl fmt::Display for clean::Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - clean::TyParamBinder(id) => { - f.write_str(&cache().typarams[ast_util::local_def(id)]) - } clean::Generic(ref name) => { f.write_str(name) } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 9f5e3be9e32..3e998166397 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Some(tcx) => tcx, None => return false }; - let def = (*tcx.def_map.borrow())[id].def_id(); + let def = tcx.def_map.borrow()[id].def_id(); if !ast_util::is_local(def) { return false } let analysis = match self.analysis { Some(analysis) => analysis, None => return false diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index effaac52716..6d6fdffa950 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -753,11 +753,10 @@ pub enum Expr_ { ExprIndex(P, P), ExprRange(Option>, Option>), - /// Variable reference, possibly containing `::` and/or - /// type parameters, e.g. foo::bar:: - ExprPath(Path), - /// A "qualified path", e.g. ` as SomeTrait>::SomeType` - ExprQPath(P), + /// Variable reference, possibly containing `::` and/or type + /// parameters, e.g. foo::bar::. Optionally "qualified", + /// e.g. ` as SomeTrait>::SomeType`. + ExprPath(Option, Path), ExprAddrOf(Mutability, P), ExprBreak(Option), @@ -778,16 +777,22 @@ pub enum Expr_ { ExprParen(P) } -/// A "qualified path": +/// The explicit Self type in a "qualified path". The actual +/// path, including the trait and the associated item, is stored +/// sepparately. `position` represents the index of the associated +/// item qualified with this Self type. /// -/// as SomeTrait>::SomeAssociatedItem -/// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~ -/// self_type trait_name item_path +/// as a::b::Trait>::AssociatedItem +/// ^~~~~ ~~~~~~~~~~~~~~^ +/// ty position = 3 +/// +/// >::AssociatedItem +/// ^~~~~ ^ +/// ty position = 0 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct QPath { - pub self_type: P, - pub trait_ref: P, - pub item_path: PathSegment, +pub struct QSelf { + pub ty: P, + pub position: usize } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -1254,16 +1259,15 @@ pub enum Ty_ { TyBareFn(P), /// A tuple (`(A, B, C, D,...)`) TyTup(Vec> ), - /// A path (`module::module::...::Type`) or primitive + /// A path (`module::module::...::Type`), optionally + /// "qualified", e.g. ` as SomeTrait>::SomeType`. /// /// Type parameters are stored in the Path itself - TyPath(Path, NodeId), + TyPath(Option, Path), /// Something like `A+B`. Note that `B` must always be a path. TyObjectSum(P, TyParamBounds), /// A type like `for<'a> Foo<&'a Bar>` TyPolyTraitRef(TyParamBounds), - /// A "qualified path", e.g. ` as SomeTrait>::SomeType` - TyQPath(P), /// No-op; kept solely so that we can pretty-print faithfully TyParen(P), /// Unused for now diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index f1228c1d363..79f0433761d 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -134,7 +134,7 @@ pub fn unop_to_string(op: UnOp) -> &'static str { } pub fn is_path(e: P) -> bool { - return match e.node { ExprPath(_) => true, _ => false }; + match e.node { ExprPath(..) => true, _ => false } } /// Get a string representation of a signed int type, with its value. @@ -488,9 +488,6 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { fn visit_ty(&mut self, typ: &Ty) { self.operation.visit_id(typ.id); - if let TyPath(_, id) = typ.node { - self.operation.visit_id(id); - } visit::walk_ty(self, typ) } @@ -564,13 +561,18 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { visit::walk_trait_item(self, tm); } - fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) { self.operation.visit_id(lifetime.id); } - fn visit_lifetime_def(&mut self, def: &'v LifetimeDef) { + fn visit_lifetime_def(&mut self, def: &LifetimeDef) { self.visit_lifetime_ref(&def.lifetime); } + + fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { + self.operation.visit_id(trait_ref.ref_id); + visit::walk_trait_ref(self, trait_ref); + } } pub fn visit_ids_for_inlined_item(item: &InlinedItem, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 656d507ed69..d916651b056 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -41,16 +41,16 @@ pub trait AstBuilder { -> ast::Path; fn qpath(&self, self_type: P, - trait_ref: P, - ident: ast::Ident ) - -> P; + trait_path: ast::Path, + ident: ast::Ident) + -> (ast::QSelf, ast::Path); fn qpath_all(&self, self_type: P, - trait_ref: P, + trait_path: ast::Path, ident: ast::Ident, lifetimes: Vec, types: Vec>, - bindings: Vec> ) - -> P; + bindings: Vec>) + -> (ast::QSelf, ast::Path); // types fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy; @@ -114,7 +114,7 @@ pub trait AstBuilder { // expressions fn expr(&self, span: Span, node: ast::Expr_) -> P; fn expr_path(&self, path: ast::Path) -> P; - fn expr_qpath(&self, span: Span, qpath: P) -> P; + fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P; fn expr_ident(&self, span: Span, id: ast::Ident) -> P; fn expr_self(&self, span: Span) -> P; @@ -346,40 +346,40 @@ impl<'a> AstBuilder for ExtCtxt<'a> { /// Constructs a qualified path. /// - /// Constructs a path like `::ident`. + /// Constructs a path like `::ident`. fn qpath(&self, self_type: P, - trait_ref: P, + trait_path: ast::Path, ident: ast::Ident) - -> P { - self.qpath_all(self_type, trait_ref, ident, Vec::new(), Vec::new(), Vec::new()) + -> (ast::QSelf, ast::Path) { + self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![]) } /// Constructs a qualified path. /// - /// Constructs a path like `::ident`. + /// Constructs a path like `::ident<'a, T, A=Bar>`. fn qpath_all(&self, self_type: P, - trait_ref: P, + trait_path: ast::Path, ident: ast::Ident, lifetimes: Vec, types: Vec>, - bindings: Vec> ) - -> P { - let segment = ast::PathSegment { + bindings: Vec>) + -> (ast::QSelf, ast::Path) { + let mut path = trait_path; + path.segments.push(ast::PathSegment { identifier: ident, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, types: OwnedSlice::from_vec(types), bindings: OwnedSlice::from_vec(bindings), }) - }; + }); - P(ast::QPath { - self_type: self_type, - trait_ref: trait_ref, - item_path: segment, - }) + (ast::QSelf { + ty: self_type, + position: path.segments.len() - 1 + }, path) } fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { @@ -398,7 +398,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn ty_path(&self, path: ast::Path) -> P { - self.ty(path.span, ast::TyPath(path, ast::DUMMY_NODE_ID)) + self.ty(path.span, ast::TyPath(None, path)) } fn ty_sum(&self, path: ast::Path, bounds: OwnedSlice) -> P { @@ -603,12 +603,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_path(&self, path: ast::Path) -> P { - self.expr(path.span, ast::ExprPath(path)) + self.expr(path.span, ast::ExprPath(None, path)) } /// Constructs a QPath expression. - fn expr_qpath(&self, span: Span, qpath: P) -> P { - self.expr(span, ast::ExprQPath(qpath)) + fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P { + self.expr(span, ast::ExprPath(Some(qself), path)) } fn expr_ident(&self, span: Span, id: ast::Ident) -> P { diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 9410a51e7a5..2303eb9645b 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -53,7 +53,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree] let e = P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprPath( + node: ast::ExprPath(None, ast::Path { span: sp, global: false, diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 91212a86958..80ef882745f 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -70,7 +70,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec!(borrowed_self()), - ret_ty: Literal(path!(bool)), + ret_ty: Literal(path_local!(bool)), attributes: attrs, combine_substructure: combine_substructure(box |a, b, c| { $f(a, b, c) diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index b109850a6bd..be4a33002aa 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -36,7 +36,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec!(borrowed_self()), - ret_ty: Literal(path!(bool)), + ret_ty: Literal(path_local!(bool)), attributes: attrs, combine_substructure: combine_substructure(box |cx, span, substr| { cs_op($op, $equal, cx, span, substr) diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index eee780f457c..973c8f5fa1e 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -30,6 +30,12 @@ macro_rules! path { ) } +macro_rules! path_local { + ($x:ident) => ( + ::ext::deriving::generic::ty::Path::new_local(stringify!($x)) + ) +} + macro_rules! pathvec_std { ($cx:expr, $first:ident :: $($rest:ident)::+) => ( if $cx.use_std { diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 22c87d978c9..3b96292323a 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -38,7 +38,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, name: "from_i64", generics: LifetimeBounds::empty(), explicit_self: None, - args: vec!(Literal(path!(i64))), + args: vec!(Literal(path_local!(i64))), ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, vec!(box Self_), @@ -53,7 +53,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, name: "from_u64", generics: LifetimeBounds::empty(), explicit_self: None, - args: vec!(Literal(path!(u64))), + args: vec!(Literal(path_local!(u64))), ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, vec!(box Self_), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 91bfe6f32dc..bea57ae14e4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -41,7 +41,7 @@ pub fn expand_type(t: P, debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty); let t = match (t.node.clone(), impl_ty) { // Expand uses of `Self` in impls to the concrete type. - (ast::Ty_::TyPath(ref path, _), Some(ref impl_ty)) => { + (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => { let path_as_ident = path_to_ident(path); // Note unhygenic comparison here. I think this is correct, since // even though `Self` is almost just a type parameter, the treatment @@ -1594,13 +1594,10 @@ mod test { impl<'v> Visitor<'v> for PathExprFinderContext { fn visit_expr(&mut self, expr: &ast::Expr) { - match expr.node { - ast::ExprPath(ref p) => { - self.path_accumulator.push(p.clone()); - // not calling visit_path, but it should be fine. - } - _ => visit::walk_expr(self, expr) + if let ast::ExprPath(None, ref p) = expr.node { + self.path_accumulator.push(p.clone()); } + visit::walk_expr(self, expr); } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 071158fcebb..32fd5b49f9a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -549,7 +549,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_ty(&mut self, t: &ast::Ty) { match t.node { - ast::TyPath(ref p, _) => { + ast::TyPath(None, ref p) => { match &*p.segments { [ast::PathSegment { identifier, .. }] => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index dae830583c4..a556b2dfd2a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -146,10 +146,6 @@ pub trait Folder : Sized { noop_fold_ty(t, self) } - fn fold_qpath(&mut self, t: P) -> P { - noop_fold_qpath(t, self) - } - fn fold_ty_binding(&mut self, t: P) -> P { noop_fold_ty_binding(t, self) } @@ -428,17 +424,19 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { } TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), TyParen(ty) => TyParen(fld.fold_ty(ty)), - TyPath(path, id) => { - let id = fld.new_id(id); - TyPath(fld.fold_path(path), id) + TyPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: fld.fold_ty(ty), + position: position + } + }); + TyPath(qself, fld.fold_path(path)) } TyObjectSum(ty, bounds) => { TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds)) } - TyQPath(qpath) => { - TyQPath(fld.fold_qpath(qpath)) - } TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) } @@ -453,19 +451,6 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { }) } -pub fn noop_fold_qpath(qpath: P, fld: &mut T) -> P { - qpath.map(|qpath| { - QPath { - self_type: fld.fold_ty(qpath.self_type), - trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)), - item_path: PathSegment { - identifier: fld.fold_ident(qpath.item_path.identifier), - parameters: fld.fold_path_parameters(qpath.item_path.parameters), - } - } - }) -} - pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, fld: &mut T) -> ForeignMod { ForeignMod { @@ -1364,8 +1349,15 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprRange(e1.map(|x| folder.fold_expr(x)), e2.map(|x| folder.fold_expr(x))) } - ExprPath(pth) => ExprPath(folder.fold_path(pth)), - ExprQPath(qpath) => ExprQPath(folder.fold_qpath(qpath)), + ExprPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: folder.fold_ty(ty), + position: position + } + }); + ExprPath(qself, folder.fold_path(path)) + } ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))), ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))), ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 43dfcbae57e..4d099529cb4 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -774,7 +774,7 @@ mod test { assert!(string_to_expr("a".to_string()) == P(ast::Expr{ id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(ast::Path { + node: ast::ExprPath(None, ast::Path { span: sp(0, 1), global: false, segments: vec!( @@ -792,7 +792,7 @@ mod test { assert!(string_to_expr("::a::b".to_string()) == P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(ast::Path { + node: ast::ExprPath(None, ast::Path { span: sp(0, 6), global: true, segments: vec!( @@ -974,7 +974,7 @@ mod test { id: ast::DUMMY_NODE_ID, node:ast::ExprRet(Some(P(ast::Expr{ id: ast::DUMMY_NODE_ID, - node:ast::ExprPath(ast::Path{ + node:ast::ExprPath(None, ast::Path{ span: sp(7, 8), global: false, segments: vec!( @@ -995,7 +995,7 @@ mod test { P(Spanned{ node: ast::StmtExpr(P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(ast::Path { + node: ast::ExprPath(None, ast::Path { span:sp(0,1), global:false, segments: vec!( @@ -1041,7 +1041,7 @@ mod test { node: ast::ItemFn(P(ast::FnDecl { inputs: vec!(ast::Arg{ ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, - node: ast::TyPath(ast::Path{ + node: ast::TyPath(None, ast::Path{ span:sp(10,13), global:false, segments: vec!( @@ -1051,7 +1051,7 @@ mod test { parameters: ast::PathParameters::none(), } ), - }, ast::DUMMY_NODE_ID), + }), span:sp(10,13) }), pat: P(ast::Pat { @@ -1084,7 +1084,7 @@ mod test { stmts: vec!(P(Spanned{ node: ast::StmtSemi(P(ast::Expr{ id: ast::DUMMY_NODE_ID, - node: ast::ExprPath( + node: ast::ExprPath(None, ast::Path{ span:sp(17,18), global:false, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fec33eddb91..f171e8279f4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -25,7 +25,7 @@ use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; use ast::{ExprBreak, ExprCall, ExprCast}; use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac, ExprRange}; -use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath}; +use ast::{ExprMethodCall, ExprParen, ExprPath}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; @@ -43,7 +43,7 @@ use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, NodeId, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; use ast::{PolyTraitRef}; -use ast::{QPath, RequiredMethod}; +use ast::{QSelf, RequiredMethod}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub, StrStyle}; @@ -53,7 +53,7 @@ use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; use ast::{TyFixedLengthVec, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; -use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath}; +use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr}; use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; use ast::{TypeImplItem, TypeTraitItem, Typedef,}; use ast::{UnnamedField, UnsafeBlock}; @@ -143,7 +143,7 @@ macro_rules! maybe_whole_expr { _ => unreachable!() }; let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprPath(pt))) + Some($p.mk_expr(span.lo, span.hi, ExprPath(None, pt))) } token::Interpolated(token::NtBlock(_)) => { // FIXME: The following avoids an issue with lexical borrowck scopes, @@ -1076,8 +1076,7 @@ impl<'a> Parser<'a> { } pub fn parse_ty_path(&mut self) -> Ty_ { - let path = self.parse_path(LifetimeAndTypesWithoutColons); - TyPath(path, ast::DUMMY_NODE_ID) + TyPath(None, self.parse_path(LifetimeAndTypesWithoutColons)) } /// parse a TyBareFn type: @@ -1525,19 +1524,36 @@ impl<'a> Parser<'a> { } else if self.eat_lt() { // QUALIFIED PATH `::item` let self_type = self.parse_ty_sum(); - self.expect_keyword(keywords::As); - let trait_ref = self.parse_trait_ref(); + + let mut path = if self.eat_keyword(keywords::As) { + self.parse_path(LifetimeAndTypesWithoutColons) + } else { + ast::Path { + span: self.span, + global: false, + segments: vec![] + } + }; + + let qself = QSelf { + ty: self_type, + position: path.segments.len() + }; + self.expect(&token::Gt); self.expect(&token::ModSep); - let item_name = self.parse_ident(); - TyQPath(P(QPath { - self_type: self_type, - trait_ref: P(trait_ref), - item_path: ast::PathSegment { - identifier: item_name, - parameters: ast::PathParameters::none() - } - })) + + path.segments.push(ast::PathSegment { + identifier: self.parse_ident(), + parameters: ast::PathParameters::none() + }); + + if path.segments.len() == 1 { + path.span.lo = self.last_span.lo; + } + path.span.hi = self.last_span.hi; + + TyPath(Some(qself), path) } else if self.check(&token::ModSep) || self.token.is_ident() || self.token.is_path() { @@ -2178,7 +2194,7 @@ impl<'a> Parser<'a> { }, token::Plain) => { self.bump(); let path = ast_util::ident_to_path(mk_sp(lo, hi), id); - ex = ExprPath(path); + ex = ExprPath(None, path); hi = self.last_span.hi; } token::OpenDelim(token::Bracket) => { @@ -2220,10 +2236,22 @@ impl<'a> Parser<'a> { if self.eat_lt() { // QUALIFIED PATH `::item::<'a, T>` let self_type = self.parse_ty_sum(); - self.expect_keyword(keywords::As); - let trait_ref = self.parse_trait_ref(); + let mut path = if self.eat_keyword(keywords::As) { + self.parse_path(LifetimeAndTypesWithoutColons) + } else { + ast::Path { + span: self.span, + global: false, + segments: vec![] + } + }; + let qself = QSelf { + ty: self_type, + position: path.segments.len() + }; self.expect(&token::Gt); self.expect(&token::ModSep); + let item_name = self.parse_ident(); let parameters = if self.eat(&token::ModSep) { self.expect_lt(); @@ -2238,15 +2266,18 @@ impl<'a> Parser<'a> { } else { ast::PathParameters::none() }; + path.segments.push(ast::PathSegment { + identifier: item_name, + parameters: parameters + }); + + if path.segments.len() == 1 { + path.span.lo = self.last_span.lo; + } + path.span.hi = self.last_span.hi; + let hi = self.span.hi; - return self.mk_expr(lo, hi, ExprQPath(P(QPath { - self_type: self_type, - trait_ref: P(trait_ref), - item_path: ast::PathSegment { - identifier: item_name, - parameters: parameters - } - }))); + return self.mk_expr(lo, hi, ExprPath(Some(qself), path)); } if self.eat_keyword(keywords::Move) { return self.parse_lambda_expr(CaptureByValue); @@ -2386,7 +2417,7 @@ impl<'a> Parser<'a> { } hi = pth.span.hi; - ex = ExprPath(pth); + ex = ExprPath(None, pth); } else { // other literal expression let lit = self.parse_lit(); @@ -3428,7 +3459,7 @@ impl<'a> Parser<'a> { let end = if self.token.is_ident() || self.token.is_path() { let path = self.parse_path(LifetimeAndTypesWithColons); let hi = self.span.hi; - self.mk_expr(lo, hi, ExprPath(path)) + self.mk_expr(lo, hi, ExprPath(None, path)) } else { self.parse_literal_maybe_minus() }; @@ -4815,10 +4846,10 @@ impl<'a> Parser<'a> { let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { // New-style trait. Reinterpret the type as a trait. match ty.node { - TyPath(ref path, node_id) => { + TyPath(None, ref path) => { Some(TraitRef { path: (*path).clone(), - ref_id: node_id, + ref_id: ty.id, }) } _ => { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 869dad867eb..af16e19c9f0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -373,7 +373,7 @@ pub fn fn_block_to_string(p: &ast::FnDecl) -> String { } pub fn path_to_string(p: &ast::Path) -> String { - $to_string(|s| s.print_path(p, false)) + $to_string(|s| s.print_path(p, false, 0)) } pub fn ident_to_string(id: &ast::Ident) -> String { @@ -729,8 +729,11 @@ impl<'a> State<'a> { &generics, None)); } - ast::TyPath(ref path, _) => { - try!(self.print_path(path, false)); + ast::TyPath(None, ref path) => { + try!(self.print_path(path, false, 0)); + } + ast::TyPath(Some(ref qself), ref path) => { + try!(self.print_qpath(path, qself, false)) } ast::TyObjectSum(ref ty, ref bounds) => { try!(self.print_type(&**ty)); @@ -739,9 +742,6 @@ impl<'a> State<'a> { ast::TyPolyTraitRef(ref bounds) => { try!(self.print_bounds("", &bounds[..])); } - ast::TyQPath(ref qpath) => { - try!(self.print_qpath(&**qpath, false)) - } ast::TyFixedLengthVec(ref ty, ref v) => { try!(word(&mut self.s, "[")); try!(self.print_type(&**ty)); @@ -1018,7 +1018,7 @@ impl<'a> State<'a> { ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _), ..}) => { try!(self.print_visibility(item.vis)); - try!(self.print_path(pth, false)); + try!(self.print_path(pth, false, 0)); try!(word(&mut self.s, "! ")); try!(self.print_ident(item.ident)); try!(self.cbox(indent_unit)); @@ -1033,7 +1033,7 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> { - self.print_path(&t.path, false) + self.print_path(&t.path, false, 0) } fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> IoResult<()> { @@ -1297,7 +1297,7 @@ impl<'a> State<'a> { ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _), ..}) => { // code copied from ItemMac: - try!(self.print_path(pth, false)); + try!(self.print_path(pth, false, 0)); try!(word(&mut self.s, "! ")); try!(self.cbox(indent_unit)); try!(self.popen()); @@ -1514,7 +1514,7 @@ impl<'a> State<'a> { match m.node { // I think it's reasonable to hide the ctxt here: ast::MacInvocTT(ref pth, ref tts, _) => { - try!(self.print_path(pth, false)); + try!(self.print_path(pth, false, 0)); try!(word(&mut self.s, "!")); match delim { token::Paren => try!(self.popen()), @@ -1584,7 +1584,7 @@ impl<'a> State<'a> { path: &ast::Path, fields: &[ast::Field], wth: &Option>) -> IoResult<()> { - try!(self.print_path(path, true)); + try!(self.print_path(path, true, 0)); if !(fields.is_empty() && wth.is_none()) { try!(word(&mut self.s, "{")); try!(self.commasep_cmnt( @@ -1852,8 +1852,12 @@ impl<'a> State<'a> { try!(self.print_expr(&**e)); } } - ast::ExprPath(ref path) => try!(self.print_path(path, true)), - ast::ExprQPath(ref qpath) => try!(self.print_qpath(&**qpath, true)), + ast::ExprPath(None, ref path) => { + try!(self.print_path(path, true, 0)) + } + ast::ExprPath(Some(ref qself), ref path) => { + try!(self.print_qpath(path, qself, true)) + } ast::ExprBreak(opt_ident) => { try!(word(&mut self.s, "break")); try!(space(&mut self.s)); @@ -2014,16 +2018,14 @@ impl<'a> State<'a> { fn print_path(&mut self, path: &ast::Path, - colons_before_params: bool) + colons_before_params: bool, + depth: usize) -> IoResult<()> { try!(self.maybe_print_comment(path.span.lo)); - if path.global { - try!(word(&mut self.s, "::")); - } - let mut first = true; - for segment in &path.segments { + let mut first = !path.global; + for segment in &path.segments[..path.segments.len()-depth] { if first { first = false } else { @@ -2039,19 +2041,24 @@ impl<'a> State<'a> { } fn print_qpath(&mut self, - qpath: &ast::QPath, + path: &ast::Path, + qself: &ast::QSelf, colons_before_params: bool) -> IoResult<()> { try!(word(&mut self.s, "<")); - try!(self.print_type(&*qpath.self_type)); - try!(space(&mut self.s)); - try!(self.word_space("as")); - try!(self.print_trait_ref(&*qpath.trait_ref)); + try!(self.print_type(&qself.ty)); + if qself.position > 0 { + try!(space(&mut self.s)); + try!(self.word_space("as")); + let depth = path.segments.len() - qself.position; + try!(self.print_path(&path, false, depth)); + } try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); - try!(self.print_ident(qpath.item_path.identifier)); - self.print_path_parameters(&qpath.item_path.parameters, colons_before_params) + let item_segment = path.segments.last().unwrap(); + try!(self.print_ident(item_segment.identifier)); + self.print_path_parameters(&item_segment.parameters, colons_before_params) } fn print_path_parameters(&mut self, @@ -2156,7 +2163,7 @@ impl<'a> State<'a> { } } ast::PatEnum(ref path, ref args_) => { - try!(self.print_path(path, true)); + try!(self.print_path(path, true, 0)); match *args_ { None => try!(word(&mut self.s, "(..)")), Some(ref args) => { @@ -2170,7 +2177,7 @@ impl<'a> State<'a> { } } ast::PatStruct(ref path, ref fields, etc) => { - try!(self.print_path(path, true)); + try!(self.print_path(path, true, 0)); try!(self.nbsp()); try!(self.word_space("{")); try!(self.commasep_cmnt( @@ -2555,7 +2562,7 @@ impl<'a> State<'a> { } } &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => { - try!(self.print_path(path, false)); + try!(self.print_path(path, false, 0)); try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&**ty)); @@ -2592,7 +2599,7 @@ impl<'a> State<'a> { pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> IoResult<()> { match vp.node { ast::ViewPathSimple(ident, ref path) => { - try!(self.print_path(path, false)); + try!(self.print_path(path, false, 0)); // FIXME(#6993) can't compare identifiers directly here if path.segments.last().unwrap().identifier.name != @@ -2606,7 +2613,7 @@ impl<'a> State<'a> { } ast::ViewPathGlob(ref path) => { - try!(self.print_path(path, false)); + try!(self.print_path(path, false, 0)); word(&mut self.s, "::*") } @@ -2614,7 +2621,7 @@ impl<'a> State<'a> { if path.segments.is_empty() { try!(word(&mut self.s, "{")); } else { - try!(self.print_path(path, false)); + try!(self.print_path(path, false, 0)); try!(word(&mut self.s, "::{")); } try!(self.commasep(Inconsistent, &idents[..], |s, w| { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 412bf0fa22a..33d8d56b4b1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -125,9 +125,6 @@ pub trait Visitor<'v> : Sized { fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) { walk_path(self, path) } - fn visit_qpath(&mut self, qpath_span: Span, qpath: &'v QPath) { - walk_qpath(self, qpath_span, qpath) - } fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { walk_path_segment(self, path_span, path_segment) } @@ -399,16 +396,16 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { walk_fn_ret_ty(visitor, &function_declaration.decl.output); walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes); } - TyPath(ref path, id) => { - visitor.visit_path(path, id); + TyPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } + visitor.visit_path(path, typ.id); } TyObjectSum(ref ty, ref bounds) => { visitor.visit_ty(&**ty); walk_ty_param_bounds_helper(visitor, bounds); } - TyQPath(ref qpath) => { - visitor.visit_qpath(typ.span, &**qpath); - } TyFixedLengthVec(ref ty, ref expression) => { visitor.visit_ty(&**ty); visitor.visit_expr(&**expression) @@ -436,14 +433,6 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { } } -pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, - qpath_span: Span, - qpath: &'v QPath) { - visitor.visit_ty(&*qpath.self_type); - visitor.visit_trait_ref(&*qpath.trait_ref); - visitor.visit_path_segment(qpath_span, &qpath.item_path); -} - pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { @@ -869,12 +858,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { walk_expr_opt(visitor, start); walk_expr_opt(visitor, end) } - ExprPath(ref path) => { + ExprPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, expression.id) } - ExprQPath(ref qpath) => { - visitor.visit_qpath(expression.span, &**qpath) - } ExprBreak(_) | ExprAgain(_) => {} ExprRet(ref optional_expression) => { walk_expr_opt(visitor, optional_expression) diff --git a/src/test/compile-fail/associated-types-in-ambiguous-context.rs b/src/test/compile-fail/associated-types-in-ambiguous-context.rs index 3999e9cbe75..becbc27138b 100644 --- a/src/test/compile-fail/associated-types-in-ambiguous-context.rs +++ b/src/test/compile-fail/associated-types-in-ambiguous-context.rs @@ -22,5 +22,8 @@ trait Grab { //~^ ERROR ambiguous associated type } +type X = std::ops::Deref::Target; +//~^ ERROR ambiguous associated type + fn main() { } diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs index 3e02a11c378..7a7406115d3 100644 --- a/src/test/compile-fail/bad-mid-path-type-params.rs +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -43,7 +43,7 @@ fn foo<'a>() { //~^ ERROR too many type parameters provided let _ = S::<'a,isize>::new::(1, 1.0); - //~^ ERROR too many lifetime parameters provided + //~^ ERROR wrong number of lifetime parameters let _: S2 = Trait::new::(1, 1.0); //~^ ERROR too many type parameters provided diff --git a/src/test/compile-fail/extern-with-type-bounds.rs b/src/test/compile-fail/extern-with-type-bounds.rs index ade8b397e00..21334e1d513 100644 --- a/src/test/compile-fail/extern-with-type-bounds.rs +++ b/src/test/compile-fail/extern-with-type-bounds.rs @@ -24,7 +24,7 @@ extern "rust-intrinsic" { // Unresolved bounds should still error. fn align_of() -> usize; - //~^ ERROR attempt to bound type parameter with a nonexistent trait `NoSuchTrait` + //~^ ERROR use of undeclared trait name `NoSuchTrait` } fn main() {} diff --git a/src/test/compile-fail/generic-impl-less-params-with-defaults.rs b/src/test/compile-fail/generic-impl-less-params-with-defaults.rs index 9fea5e609d1..5fa429445a3 100644 --- a/src/test/compile-fail/generic-impl-less-params-with-defaults.rs +++ b/src/test/compile-fail/generic-impl-less-params-with-defaults.rs @@ -19,5 +19,5 @@ impl Foo { fn main() { Foo::::new(); - //~^ ERROR too few type parameters provided + //~^ ERROR wrong number of type arguments } diff --git a/src/test/compile-fail/generic-impl-more-params-with-defaults.rs b/src/test/compile-fail/generic-impl-more-params-with-defaults.rs index 73c19aa012d..d3babb8982d 100644 --- a/src/test/compile-fail/generic-impl-more-params-with-defaults.rs +++ b/src/test/compile-fail/generic-impl-more-params-with-defaults.rs @@ -21,5 +21,5 @@ impl Vec { fn main() { Vec::::new(); - //~^ ERROR too many type parameters provided + //~^ ERROR wrong number of type arguments } diff --git a/src/test/compile-fail/glob-resolve1.rs b/src/test/compile-fail/glob-resolve1.rs index fce8a07d727..181503db818 100644 --- a/src/test/compile-fail/glob-resolve1.rs +++ b/src/test/compile-fail/glob-resolve1.rs @@ -36,9 +36,6 @@ fn main() { import(); //~ ERROR: unresolved foo::(); //~ ERROR: undeclared - //~^ ERROR: undeclared foo::(); //~ ERROR: undeclared - //~^ ERROR: undeclared foo::(); //~ ERROR: undeclared - //~^ ERROR: undeclared } diff --git a/src/test/compile-fail/impl-duplicate-methods.rs b/src/test/compile-fail/impl-duplicate-methods.rs index c6ce4d04e10..c0c951dd8b1 100644 --- a/src/test/compile-fail/impl-duplicate-methods.rs +++ b/src/test/compile-fail/impl-duplicate-methods.rs @@ -11,7 +11,7 @@ struct Foo; impl Foo { fn orange(&self){} - fn orange(&self){} //~ ERROR error: duplicate definition of value `orange` + fn orange(&self){} //~ ERROR error: duplicate method in trait impl } fn main() {} diff --git a/src/test/compile-fail/inner-static-type-parameter.rs b/src/test/compile-fail/inner-static-type-parameter.rs index abd7efe0e8e..cf2a70deee5 100644 --- a/src/test/compile-fail/inner-static-type-parameter.rs +++ b/src/test/compile-fail/inner-static-type-parameter.rs @@ -14,7 +14,8 @@ enum Bar { What } fn foo() { static a: Bar = Bar::What; - //~^ ERROR: cannot use an outer type parameter in this context + //~^ ERROR cannot use an outer type parameter in this context + //~| ERROR use of undeclared type name `T` } fn main() { diff --git a/src/test/compile-fail/issue-13641.rs b/src/test/compile-fail/issue-13641.rs index 3f5d29a8217..51b6dc0d078 100644 --- a/src/test/compile-fail/issue-13641.rs +++ b/src/test/compile-fail/issue-13641.rs @@ -17,9 +17,9 @@ mod a { fn main() { a::Foo::new(); - //~^ ERROR: static method `new` is inaccessible + //~^ ERROR: method `new` is inaccessible //~^^ NOTE: struct `Foo` is private a::Bar::new(); - //~^ ERROR: static method `new` is inaccessible + //~^ ERROR: method `new` is inaccessible //~^^ NOTE: enum `Bar` is private } diff --git a/src/test/compile-fail/issue-14254.rs b/src/test/compile-fail/issue-14254.rs index 74eea0c57a0..ce5fa1f1fe1 100644 --- a/src/test/compile-fail/issue-14254.rs +++ b/src/test/compile-fail/issue-14254.rs @@ -29,7 +29,7 @@ impl Foo for *const BarTy { baz(); //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`? a; - //~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`? + //~^ ERROR: unresolved name `a` } } @@ -42,11 +42,11 @@ impl<'a> Foo for &'a BarTy { y; //~^ ERROR: unresolved name `y`. Did you mean `self.y`? a; - //~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`? + //~^ ERROR: unresolved name `a` bah; //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`? b; - //~^ ERROR: unresolved name `b`. Did you mean to call `self.b`? + //~^ ERROR: unresolved name `b` } } @@ -59,11 +59,11 @@ impl<'a> Foo for &'a mut BarTy { y; //~^ ERROR: unresolved name `y`. Did you mean `self.y`? a; - //~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`? + //~^ ERROR: unresolved name `a` bah; //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`? b; - //~^ ERROR: unresolved name `b`. Did you mean to call `self.b`? + //~^ ERROR: unresolved name `b` } } diff --git a/src/test/compile-fail/issue-19883.rs b/src/test/compile-fail/issue-19883.rs index bbc5ee6c8f3..c6ff82364b3 100644 --- a/src/test/compile-fail/issue-19883.rs +++ b/src/test/compile-fail/issue-19883.rs @@ -15,18 +15,11 @@ trait From { } trait To { - // This is a typo, the return type should be `>::Output` - fn to>( - self - //~^ error: the trait `core::marker::Sized` is not implemented - ) -> + fn to>(self) -> >::Dst - //~^ error: the trait `core::marker::Sized` is not implemented + //~^ ERROR use of undeclared associated type `From::Dst` { - From::from( - //~^ error: the trait `core::marker::Sized` is not implemented - self - ) + From::from(self) } } diff --git a/src/test/compile-fail/issue-21202.rs b/src/test/compile-fail/issue-21202.rs index 5c1de6dfc55..05485008e51 100644 --- a/src/test/compile-fail/issue-21202.rs +++ b/src/test/compile-fail/issue-21202.rs @@ -18,7 +18,7 @@ mod B { use crate1::A::Foo; fn bar(f: Foo) { Foo::foo(&f); - //~^ ERROR: function `foo` is private + //~^ ERROR: method `foo` is private } } diff --git a/src/test/compile-fail/issue-2356.rs b/src/test/compile-fail/issue-2356.rs index f0ae0eb59f5..48cc27e2289 100644 --- a/src/test/compile-fail/issue-2356.rs +++ b/src/test/compile-fail/issue-2356.rs @@ -36,7 +36,7 @@ impl Groom for cat { shave(4); //~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`? purr(); - //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`? + //~^ ERROR: unresolved name `purr` } } @@ -45,13 +45,13 @@ impl cat { fn purr_louder() { static_method(); - //~^ ERROR: unresolved name `static_method`. Did you mean to call `cat::static_method` + //~^ ERROR: unresolved name `static_method` purr(); - //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`? + //~^ ERROR: unresolved name `purr` purr(); - //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`? + //~^ ERROR: unresolved name `purr` purr(); - //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`? + //~^ ERROR: unresolved name `purr` } } @@ -65,7 +65,7 @@ impl cat { fn purr(&self) { grow_older(); - //~^ ERROR: unresolved name `grow_older`. Did you mean to call `cat::grow_older` + //~^ ERROR: unresolved name `grow_older` shave(); //~^ ERROR: unresolved name `shave` } @@ -79,7 +79,7 @@ impl cat { whiskers = 4; //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`? purr_louder(); - //~^ ERROR: unresolved name `purr_louder`. Did you mean to call `cat::purr_louder` + //~^ ERROR: unresolved name `purr_louder` } } diff --git a/src/test/compile-fail/issue-3521-2.rs b/src/test/compile-fail/issue-3521-2.rs index 678618d7216..ad5bc4e445c 100644 --- a/src/test/compile-fail/issue-3521-2.rs +++ b/src/test/compile-fail/issue-3521-2.rs @@ -11,7 +11,9 @@ fn main() { let foo = 100; - static y: isize = foo + 1; //~ ERROR: attempt to use a non-constant value in a constant + static y: isize = foo + 1; + //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR unresolved name `foo` println!("{}", y); } diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index c49959c16a6..f06aa45ac38 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -13,7 +13,9 @@ fn main() { #[derive(Debug)] enum Stuff { - Bar = foo //~ ERROR attempt to use a non-constant value in a constant + Bar = foo + //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR unresolved name `foo` } println!("{}", Stuff::Bar); diff --git a/src/test/compile-fail/issue-3668-2.rs b/src/test/compile-fail/issue-3668-2.rs index 0577b152723..a09c8090de0 100644 --- a/src/test/compile-fail/issue-3668-2.rs +++ b/src/test/compile-fail/issue-3668-2.rs @@ -9,7 +9,9 @@ // except according to those terms. fn f(x:isize) { - static child: isize = x + 1; //~ ERROR attempt to use a non-constant value in a constant + static child: isize = x + 1; + //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR unresolved name `x` } fn main() {} diff --git a/src/test/compile-fail/issue-3668.rs b/src/test/compile-fail/issue-3668.rs index 9c31dc1e38e..9b7476244f0 100644 --- a/src/test/compile-fail/issue-3668.rs +++ b/src/test/compile-fail/issue-3668.rs @@ -17,6 +17,7 @@ impl PTrait for P { fn getChildOption(&self) -> Option> { static childVal: Box

= self.child.get(); //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR unresolved name `self` panic!(); } } diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index e4f7521c333..2652fb5dfc2 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -30,7 +30,5 @@ impl ToString_ for Point { fn main() { let p = Point::new(0.0, 0.0); - //~^ ERROR unresolved name `Point::new` - //~^^ ERROR failed to resolve. Use of undeclared type or module `Point` println!("{}", p.to_string()); } diff --git a/src/test/compile-fail/issue-4265.rs b/src/test/compile-fail/issue-4265.rs index b4bc7ecdc5f..ab18e0bcddc 100644 --- a/src/test/compile-fail/issue-4265.rs +++ b/src/test/compile-fail/issue-4265.rs @@ -17,7 +17,7 @@ impl Foo { Foo { baz: 0 }.bar(); } - fn bar() { //~ ERROR duplicate definition of value `bar` + fn bar() { //~ ERROR duplicate method in trait impl } } diff --git a/src/test/compile-fail/issue-7607-1.rs b/src/test/compile-fail/issue-7607-1.rs index 48fc393d0da..4ac90177609 100644 --- a/src/test/compile-fail/issue-7607-1.rs +++ b/src/test/compile-fail/issue-7607-1.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - struct Foo { x: isize } -impl Fo { //~ERROR inherent implementations are not allowed for types not defined in the current module +impl Fo { //~ ERROR use of undeclared type name `Fo` fn foo() {} } diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs index 6c5bac5e0cb..2ef0a75f77b 100644 --- a/src/test/compile-fail/issue-8767.rs +++ b/src/test/compile-fail/issue-8767.rs @@ -10,7 +10,7 @@ // ignore-tidy-linelength -impl B { //~ERROR inherent implementations are not allowed for types not defined in the current module +impl B { //~ ERROR use of undeclared type name `B` } fn main() { diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 88f2cbdea6d..90792848855 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -29,45 +29,104 @@ mod cross_crate { use lint_stability::*; fn test() { + type Foo = MethodTester; let foo = MethodTester; deprecated(); //~ ERROR use of deprecated item foo.method_deprecated(); //~ ERROR use of deprecated item + Foo::method_deprecated(&foo); //~ ERROR use of deprecated item + ::method_deprecated(&foo); //~ ERROR use of deprecated item foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item deprecated_text(); //~ ERROR use of deprecated item: text foo.method_deprecated_text(); //~ ERROR use of deprecated item: text + Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text deprecated_unstable(); //~ ERROR use of deprecated item //~^ WARNING use of unstable library feature foo.method_deprecated_unstable(); //~ ERROR use of deprecated item //~^ WARNING use of unstable library feature + Foo::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature + ::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item //~^ WARNING use of unstable library feature + Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature deprecated_unstable_text(); //~ ERROR use of deprecated item: text //~^ WARNING use of unstable library feature foo.method_deprecated_unstable_text(); //~ ERROR use of deprecated item: text //~^ WARNING use of unstable library feature + Foo::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature + ::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text //~^ WARNING use of unstable library feature + Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature unstable(); //~ WARNING use of unstable library feature foo.method_unstable(); //~ WARNING use of unstable library feature + Foo::method_unstable(&foo); //~ WARNING use of unstable library feature + ::method_unstable(&foo); //~ WARNING use of unstable library feature foo.trait_unstable(); //~ WARNING use of unstable library feature + Trait::trait_unstable(&foo); //~ WARNING use of unstable library feature + ::trait_unstable(&foo); //~ WARNING use of unstable library feature + ::trait_unstable(&foo); //~ WARNING use of unstable library feature - unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text - foo.method_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text - foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text + unstable_text(); + //~^ WARNING use of unstable library feature 'test_feature': text + foo.method_unstable_text(); + //~^ WARNING use of unstable library feature 'test_feature': text + Foo::method_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text + ::method_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text + foo.trait_unstable_text(); + //~^ WARNING use of unstable library feature 'test_feature': text + Trait::trait_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text + ::trait_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text + ::trait_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text stable(); foo.method_stable(); + Foo::method_stable(&foo); + ::method_stable(&foo); foo.trait_stable(); + Trait::trait_stable(&foo); + ::trait_stable(&foo); + ::trait_stable(&foo); stable_text(); foo.method_stable_text(); + Foo::method_stable_text(&foo); + ::method_stable_text(&foo); foo.trait_stable_text(); + Trait::trait_stable_text(&foo); + ::trait_stable_text(&foo); + ::trait_stable_text(&foo); let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item let _ = DeprecatedUnstableStruct { i: 0 }; //~ ERROR use of deprecated item @@ -104,16 +163,47 @@ mod cross_crate { macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text } - fn test_method_param(foo: F) { + fn test_method_param(foo: Foo) { foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item //~^ WARNING use of unstable library feature + Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item + //~^ WARNING use of unstable library feature foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text //~^ WARNING use of unstable library feature + Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature + ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + //~^ WARNING use of unstable library feature foo.trait_unstable(); //~ WARNING use of unstable library feature - foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text + Trait::trait_unstable(&foo); //~ WARNING use of unstable library feature + ::trait_unstable(&foo); //~ WARNING use of unstable library feature + ::trait_unstable(&foo); //~ WARNING use of unstable library feature + foo.trait_unstable_text(); + //~^ WARNING use of unstable library feature 'test_feature': text + Trait::trait_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text + ::trait_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text + ::trait_unstable_text(&foo); + //~^ WARNING use of unstable library feature 'test_feature': text foo.trait_stable(); + Trait::trait_stable(&foo); + ::trait_stable(&foo); + ::trait_stable(&foo); } fn test_method_object(foo: &Trait) { @@ -124,7 +214,8 @@ mod cross_crate { foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text //~^ WARNING use of unstable library feature foo.trait_unstable(); //~ WARNING use of unstable library feature - foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text + foo.trait_unstable_text(); + //~^ WARNING use of unstable library feature 'test_feature': text foo.trait_stable(); } @@ -264,31 +355,62 @@ mod this_crate { // errors, because other stability attributes now have meaning // only *across* crates, not within a single crate. + type Foo = MethodTester; let foo = MethodTester; deprecated(); //~ ERROR use of deprecated item foo.method_deprecated(); //~ ERROR use of deprecated item + Foo::method_deprecated(&foo); //~ ERROR use of deprecated item + ::method_deprecated(&foo); //~ ERROR use of deprecated item foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item deprecated_text(); //~ ERROR use of deprecated item: text foo.method_deprecated_text(); //~ ERROR use of deprecated item: text + Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text unstable(); foo.method_unstable(); + Foo::method_unstable(&foo); + ::method_unstable(&foo); foo.trait_unstable(); + Trait::trait_unstable(&foo); + ::trait_unstable(&foo); + ::trait_unstable(&foo); unstable_text(); foo.method_unstable_text(); + Foo::method_unstable_text(&foo); + ::method_unstable_text(&foo); foo.trait_unstable_text(); + Trait::trait_unstable_text(&foo); + ::trait_unstable_text(&foo); + ::trait_unstable_text(&foo); stable(); foo.method_stable(); + Foo::method_stable(&foo); + ::method_stable(&foo); foo.trait_stable(); + Trait::trait_stable(&foo); + ::trait_stable(&foo); + ::trait_stable(&foo); stable_text(); foo.method_stable_text(); + Foo::method_stable_text(&foo); + ::method_stable_text(&foo); foo.trait_stable_text(); + Trait::trait_stable_text(&foo); + ::trait_stable_text(&foo); + ::trait_stable_text(&foo); let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item let _ = UnstableStruct { i: 0 }; @@ -307,12 +429,27 @@ mod this_crate { let _ = StableTupleStruct (1); } - fn test_method_param(foo: F) { + fn test_method_param(foo: Foo) { foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text foo.trait_unstable(); + Trait::trait_unstable(&foo); + ::trait_unstable(&foo); + ::trait_unstable(&foo); foo.trait_unstable_text(); + Trait::trait_unstable_text(&foo); + ::trait_unstable_text(&foo); + ::trait_unstable_text(&foo); foo.trait_stable(); + Trait::trait_stable(&foo); + ::trait_stable(&foo); + ::trait_stable(&foo); } fn test_method_object(foo: &Trait) { diff --git a/src/test/compile-fail/method-macro-backtrace.rs b/src/test/compile-fail/method-macro-backtrace.rs index f4740492651..c9ef2df8e13 100644 --- a/src/test/compile-fail/method-macro-backtrace.rs +++ b/src/test/compile-fail/method-macro-backtrace.rs @@ -29,7 +29,7 @@ impl S { // Cause an error. It shouldn't have any macro backtrace frames. fn bar(&self) { } - fn bar(&self) { } //~ ERROR duplicate definition + fn bar(&self) { } //~ ERROR duplicate method } fn main() { } diff --git a/src/test/compile-fail/no-implicit-prelude-nested.rs b/src/test/compile-fail/no-implicit-prelude-nested.rs index 2fb097f111d..526750257d2 100644 --- a/src/test/compile-fail/no-implicit-prelude-nested.rs +++ b/src/test/compile-fail/no-implicit-prelude-nested.rs @@ -18,11 +18,11 @@ mod foo { mod baz { struct Test; - impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Add for Test {} //~ ERROR: use of undeclared trait + impl Clone for Test {} //~ ERROR: use of undeclared trait + impl Iterator for Test {} //~ ERROR: use of undeclared trait + impl ToString for Test {} //~ ERROR: use of undeclared trait + impl Writer for Test {} //~ ERROR: use of undeclared trait fn foo() { drop(2) //~ ERROR: unresolved name @@ -30,11 +30,11 @@ mod foo { } struct Test; - impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Add for Test {} //~ ERROR: use of undeclared trait + impl Clone for Test {} //~ ERROR: use of undeclared trait + impl Iterator for Test {} //~ ERROR: use of undeclared trait + impl ToString for Test {} //~ ERROR: use of undeclared trait + impl Writer for Test {} //~ ERROR: use of undeclared trait fn foo() { drop(2) //~ ERROR: unresolved name @@ -45,11 +45,11 @@ fn qux() { #[no_implicit_prelude] mod qux_inner { struct Test; - impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait - impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Add for Test {} //~ ERROR: use of undeclared trait + impl Clone for Test {} //~ ERROR: use of undeclared trait + impl Iterator for Test {} //~ ERROR: use of undeclared trait + impl ToString for Test {} //~ ERROR: use of undeclared trait + impl Writer for Test {} //~ ERROR: use of undeclared trait fn foo() { drop(2) //~ ERROR: unresolved name diff --git a/src/test/compile-fail/no-implicit-prelude.rs b/src/test/compile-fail/no-implicit-prelude.rs index c0f7bea25b5..c4bcd33b93b 100644 --- a/src/test/compile-fail/no-implicit-prelude.rs +++ b/src/test/compile-fail/no-implicit-prelude.rs @@ -17,11 +17,11 @@ // fail with the same error message). struct Test; -impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait -impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait -impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait -impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait -impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait +impl Add for Test {} //~ ERROR: use of undeclared trait +impl Clone for Test {} //~ ERROR: use of undeclared trait +impl Iterator for Test {} //~ ERROR: use of undeclared trait +impl ToString for Test {} //~ ERROR: use of undeclared trait +impl Writer for Test {} //~ ERROR: use of undeclared trait fn main() { drop(2) //~ ERROR: unresolved name diff --git a/src/test/compile-fail/resolve-unknown-trait.rs b/src/test/compile-fail/resolve-unknown-trait.rs index 0d0dc0a05d1..3983a84f6ad 100644 --- a/src/test/compile-fail/resolve-unknown-trait.rs +++ b/src/test/compile-fail/resolve-unknown-trait.rs @@ -10,11 +10,11 @@ trait NewTrait : SomeNonExistentTrait {} -//~^ ERROR attempt to derive a nonexistent trait `SomeNonExistentTrait` +//~^ ERROR use of undeclared trait name `SomeNonExistentTrait` impl SomeNonExistentTrait for isize {} -//~^ ERROR attempt to implement a nonexistent trait `SomeNonExistentTrait` +//~^ ERROR use of undeclared trait name `SomeNonExistentTrait` fn f() {} -//~^ ERROR attempt to bound type parameter with a nonexistent trait `SomeNonExistentTrait` +//~^ ERROR use of undeclared trait name `SomeNonExistentTrait` diff --git a/src/test/compile-fail/trait-impl-for-module.rs b/src/test/compile-fail/trait-impl-for-module.rs index 28d20483c7e..969b6398fdb 100644 --- a/src/test/compile-fail/trait-impl-for-module.rs +++ b/src/test/compile-fail/trait-impl-for-module.rs @@ -14,7 +14,7 @@ mod a { trait A { } -impl A for a { //~ERROR found module name used as a type +impl A for a { //~ ERROR use of undeclared type name `a` } fn main() { diff --git a/src/test/compile-fail/trait-or-new-type-instead.rs b/src/test/compile-fail/trait-or-new-type-instead.rs index e621d77a65c..3aec23a55b8 100644 --- a/src/test/compile-fail/trait-or-new-type-instead.rs +++ b/src/test/compile-fail/trait-or-new-type-instead.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - -impl Option { //~ERROR inherent implementations are not allowed for types not defined in the current module +impl Option { +//~^ ERROR cannot associate methods with a type outside the crate the type is defined in pub fn foo(&self) { } } diff --git a/src/test/compile-fail/ufcs-qpath-missing-params.rs b/src/test/compile-fail/ufcs-qpath-missing-params.rs index f4e18265fd9..b3fe178dc45 100644 --- a/src/test/compile-fail/ufcs-qpath-missing-params.rs +++ b/src/test/compile-fail/ufcs-qpath-missing-params.rs @@ -12,5 +12,5 @@ use std::borrow::IntoCow; fn main() { ::into_cow("foo".to_string()); - //~^ ERROR wrong number of type arguments: expected 1, found 0 + //~^ ERROR too few type parameters provided: expected 1 parameter(s) } diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs index 12f62d805e1..f28bf7acadd 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs @@ -10,7 +10,7 @@ #![feature(unboxed_closures)] -fn f isize>(x: F) {} //~ ERROR nonexistent trait `Nonexist` +fn f isize>(x: F) {} //~ ERROR undeclared trait name `Nonexist` type Typedef = isize; diff --git a/src/test/compile-fail/use-from-trait.rs b/src/test/compile-fail/use-from-trait.rs index 2a97155dd2e..49d8622976b 100644 --- a/src/test/compile-fail/use-from-trait.rs +++ b/src/test/compile-fail/use-from-trait.rs @@ -11,7 +11,7 @@ use Trait::foo; //~^ ERROR `foo` is not directly importable use Foo::new; -//~^ ERROR `new` is not directly importable +//~^ ERROR unresolved import `Foo::new`. Not a module `Foo` pub trait Trait { fn foo(); diff --git a/src/test/run-pass/impl-inherent-non-conflict.rs b/src/test/run-pass/impl-inherent-non-conflict.rs new file mode 100644 index 00000000000..663ed24d60e --- /dev/null +++ b/src/test/run-pass/impl-inherent-non-conflict.rs @@ -0,0 +1,31 @@ +// 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. + +// Ensure that an user-defined type admits multiple inherent methods +// with the same name, which can be called on values that have a +// precise enough type to allow distinguishing between the methods. + +struct Foo(T); + +impl Foo { + fn bar(&self) -> i32 { self.0 as i32 } +} + +impl Foo { + fn bar(&self) -> i32 { -(self.0 as i32) } +} + +fn main() { + let foo_u = Foo::(5); + assert_eq!(foo_u.bar(), 5); + + let foo_i = Foo::(3); + assert_eq!(foo_i.bar(), -3); +} diff --git a/src/test/run-pass/impl-inherent-prefer-over-trait.rs b/src/test/run-pass/impl-inherent-prefer-over-trait.rs new file mode 100644 index 00000000000..3031228b3ab --- /dev/null +++ b/src/test/run-pass/impl-inherent-prefer-over-trait.rs @@ -0,0 +1,38 @@ +// 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. + +struct Foo; + +trait Trait { + fn bar(&self); +} + +// Inherent impls should be preferred over trait ones. +impl Foo { + fn bar(&self) {} +} + +impl Trait { + fn baz(_: &Foo) {} +} + +impl Trait for Foo { + fn bar(&self) { panic!("wrong method called!") } +} + +fn main() { + Foo.bar(); + Foo::bar(&Foo); + ::bar(&Foo); + + // Should work even if Trait::baz doesn't exist. + // N.B: `::bar` would be ambiguous. + ::baz(&Foo); +} diff --git a/src/test/compile-fail/trait-impl-2.rs b/src/test/run-pass/impl-not-adjacent-to-type.rs similarity index 53% rename from src/test/compile-fail/trait-impl-2.rs rename to src/test/run-pass/impl-not-adjacent-to-type.rs index 303e3d93744..c1dc68b2456 100644 --- a/src/test/compile-fail/trait-impl-2.rs +++ b/src/test/run-pass/impl-not-adjacent-to-type.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test calling methods on an impl for a bare trait. This test checks trait impls -// must be in the same module as the trait. - -mod Foo { - trait T {} -} - -mod Bar { - impl<'a> ::Foo::T+'a { //~ERROR: inherent implementations may only be implemented in the same - fn foo(&self) {} +mod foo { + pub struct Point { + pub x: i32, + pub y: i32, } } -fn main() {} +impl foo::Point { + fn x(&self) -> i32 { self.x } +} + +fn main() { + assert_eq!((foo::Point { x: 1, y: 3}).x(), 1); +} diff --git a/src/test/compile-fail/issue-12729.rs b/src/test/run-pass/issue-12729.rs similarity index 80% rename from src/test/compile-fail/issue-12729.rs rename to src/test/run-pass/issue-12729.rs index ae033bbf38d..09c0c8604ad 100644 --- a/src/test/compile-fail/issue-12729.rs +++ b/src/test/run-pass/issue-12729.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - pub struct Foo; mod bar { use Foo; - impl Foo { //~ERROR inherent implementations are only allowed on types defined in the current module + impl Foo { fn baz(&self) {} } } diff --git a/src/test/compile-fail/issue-7607-2.rs b/src/test/run-pass/issue-7607-2.rs similarity index 81% rename from src/test/compile-fail/issue-7607-2.rs rename to src/test/run-pass/issue-7607-2.rs index 9541899b469..c52051fab96 100644 --- a/src/test/compile-fail/issue-7607-2.rs +++ b/src/test/run-pass/issue-7607-2.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - pub mod a { pub struct Foo { a: usize } } pub mod b { use a::Foo; - impl Foo { //~ERROR inherent implementations are only allowed on types defined in the current module + impl Foo { fn bar(&self) { } } } diff --git a/src/test/compile-fail/impl-not-adjacent-to-type.rs b/src/test/run-pass/trait-impl-2.rs similarity index 64% rename from src/test/compile-fail/impl-not-adjacent-to-type.rs rename to src/test/run-pass/trait-impl-2.rs index 7a7673d871d..abc35bcc29d 100644 --- a/src/test/compile-fail/impl-not-adjacent-to-type.rs +++ b/src/test/run-pass/trait-impl-2.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,17 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -mod foo { - pub struct Foo { - x: isize, - y: isize, +pub mod Foo { + pub trait Trait { + fn foo(&self); } } -impl foo::Foo { -//~^ ERROR implementations may only be implemented in the same module - fn bar() {} +mod Bar { + impl<'a> ::Foo::Trait+'a { + fn bar(&self) { self.foo() } + } } fn main() {} - diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs similarity index 53% rename from src/test/run-pass/const-polymorphic-paths.rs rename to src/test/run-pass/ufcs-polymorphic-paths.rs index dce12030f79..29b1c8f81d3 100644 --- a/src/test/run-pass/const-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -27,11 +27,11 @@ struct Newt(T); fn id(x: T) -> T { x } fn eq(a: T, b: T) -> bool { a == b } fn u8_as_i8(x: u8) -> i8 { x as i8 } -fn odd(x: uint) -> bool { x % 2 == 1 } +fn odd(x: usize) -> bool { x % 2 == 1 } fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() } trait Size: Sized { - fn size() -> uint { std::mem::size_of::() } + fn size() -> usize { std::mem::size_of::() } } impl Size for T {} @@ -47,24 +47,26 @@ macro_rules! tests { tests! { // Free function. - id, fn(int) -> int, (5); - id::, fn(int) -> int, (5); + id, fn(i32) -> i32, (5); + id::, fn(i32) -> i32, (5); // Enum variant constructor. - Some, fn(int) -> Option, (5); - Some::, fn(int) -> Option, (5); + Some, fn(i32) -> Option, (5); + Some::, fn(i32) -> Option, (5); // Tuple struct constructor. - Newt, fn(int) -> Newt, (5); - Newt::, fn(int) -> Newt, (5); + Newt, fn(i32) -> Newt, (5); + Newt::, fn(i32) -> Newt, (5); // Inherent static methods. Vec::new, fn() -> Vec<()>, (); Vec::<()>::new, fn() -> Vec<()>, (); - Vec::with_capacity, fn(uint) -> Vec<()>, (5); - Vec::<()>::with_capacity, fn(uint) -> Vec<()>, (5); - BitVec::from_fn, fn(uint, fn(uint) -> bool) -> BitVec, (5, odd); - BitVec::from_fn:: bool>, fn(uint, fn(uint) -> bool) -> BitVec, (5, odd); + >::new, fn() -> Vec<()>, (); + Vec::with_capacity, fn(usize) -> Vec<()>, (5); + Vec::<()>::with_capacity, fn(usize) -> Vec<()>, (5); + >::with_capacity, fn(usize) -> Vec<()>, (5); + BitVec::from_fn, fn(usize, fn(usize) -> bool) -> BitVec, (5, odd); + BitVec::from_fn:: bool>, fn(usize, fn(usize) -> bool) -> BitVec, (5, odd); // Inherent non-static method. Vec::map_in_place, fn(Vec, fn(u8) -> i8) -> Vec, (vec![b'f', b'o', b'o'], u8_as_i8); @@ -77,29 +79,52 @@ tests! { // , (vec![b'f', b'o', b'o'], u8_as_i8); // Trait static methods. - ::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()); + bool::size, fn() -> usize, (); + ::size, fn() -> usize, (); + ::size, fn() -> usize, (); + + Default::default, fn() -> i32, (); + i32::default, fn() -> i32, (); + ::default, fn() -> i32, (); + ::default, fn() -> i32, (); + + Rand::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + i32::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + ::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + ::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + Rand::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + i32::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + ::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + ::rand::, fn(&mut DummyRng) -> i32, (&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()); - as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, + Clone::clone, fn(&i32) -> i32, (&5); + i32::clone, fn(&i32) -> i32, (&5); + ::clone, fn(&i32) -> i32, (&5); + ::clone, fn(&i32) -> i32, (&5); + + FromIterator::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); + Vec::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); + >::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, + as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); - FromIterator::from_iter::>, fn(OptionIter) -> Vec, + FromIterator::from_iter::>, fn(OptionIter) -> Vec, (Some(5).into_iter()); - as FromIterator<_>>::from_iter::>, fn(OptionIter) -> Vec, + as FromIterator<_>>::from_iter::>, fn(OptionIter) -> Vec, (Some(5).into_iter()); + Add::add, fn(i32, i32) -> i32, (5, 6); + i32::add, fn(i32, i32) -> i32, (5, 6); + ::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); + + String::into_cow, fn(String) -> Cow<'static, str>, + ("foo".to_string()); + ::into_cow, fn(String) -> Cow<'static, str>, + ("foo".to_string()); >::into_cow, fn(String) -> Cow<'static, str>, ("foo".to_string()); >::into_cow, fn(String) -> Cow<'static, str>,