1
Fork 0

rustc_resolve: don't handle impl items as if they were modules.

This commit is contained in:
Eduard Burtescu 2015-02-20 08:17:05 +02:00
parent 6700166442
commit 06f362aeb3
24 changed files with 157 additions and 385 deletions

View file

@ -51,6 +51,7 @@ use middle::dependency_format;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem}; use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem};
use middle::mem_categorization as mc; use middle::mem_categorization as mc;
use middle::privacy::LastPrivateMap;
use middle::region; use middle::region;
use middle::resolve_lifetime; use middle::resolve_lifetime;
use middle::infer; use middle::infer;
@ -683,6 +684,7 @@ pub struct ctxt<'tcx> {
pub sess: Session, pub sess: Session,
pub def_map: DefMap, pub def_map: DefMap,
pub partial_def_map: PartialDefMap, pub partial_def_map: PartialDefMap,
pub last_private_map: RefCell<LastPrivateMap>,
pub named_region_map: resolve_lifetime::NamedRegionMap, pub named_region_map: resolve_lifetime::NamedRegionMap,
@ -2426,6 +2428,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
arenas: &'tcx CtxtArenas<'tcx>, arenas: &'tcx CtxtArenas<'tcx>,
def_map: DefMap, def_map: DefMap,
partial_def_map: PartialDefMap, partial_def_map: PartialDefMap,
last_private_map: LastPrivateMap,
named_region_map: resolve_lifetime::NamedRegionMap, named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>, map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>, freevars: RefCell<FreevarMap>,
@ -2449,6 +2452,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
sess: s, sess: s,
def_map: def_map, def_map: def_map,
partial_def_map: partial_def_map, partial_def_map: partial_def_map,
last_private_map: RefCell::new(last_private_map),
region_maps: region_maps, region_maps: region_maps,
node_types: RefCell::new(FnvHashMap()), node_types: RefCell::new(FnvHashMap()),
item_substs: RefCell::new(NodeMap()), item_substs: RefCell::new(NodeMap()),

View file

@ -609,6 +609,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
arenas, arenas,
def_map, def_map,
partial_def_map, partial_def_map,
last_private_map,
named_region_map, named_region_map,
ast_map, ast_map,
freevars, freevars,
@ -622,10 +623,9 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
time(time_passes, "const checking", (), |_| time(time_passes, "const checking", (), |_|
middle::check_const::check_crate(&ty_cx)); middle::check_const::check_crate(&ty_cx));
let maps = (external_exports, last_private_map);
let (exported_items, public_items) = let (exported_items, public_items) =
time(time_passes, "privacy checking", maps, |(a, b)| time(time_passes, "privacy checking", (), |_|
rustc_privacy::check_crate(&ty_cx, &export_map, a, b)); rustc_privacy::check_crate(&ty_cx, &export_map, external_exports));
// Do not move this check past lint // Do not move this check past lint
time(time_passes, "stability index", (), |_| time(time_passes, "stability index", (), |_|

View file

@ -38,8 +38,7 @@ use rustc::middle::def;
use rustc::middle::privacy::ImportUse::*; use rustc::middle::privacy::ImportUse::*;
use rustc::middle::privacy::LastPrivate::*; use rustc::middle::privacy::LastPrivate::*;
use rustc::middle::privacy::PrivateDep::*; use rustc::middle::privacy::PrivateDep::*;
use rustc::middle::privacy::{ExportedItems, PublicItems, LastPrivateMap}; use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems};
use rustc::middle::privacy::{ExternalExports};
use rustc::middle::ty::{MethodTypeParam, MethodStatic}; use rustc::middle::ty::{MethodTypeParam, MethodStatic};
use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam}; use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam};
use rustc::middle::ty::{MethodStaticClosure, MethodObject}; use rustc::middle::ty::{MethodStaticClosure, MethodObject};
@ -379,7 +378,6 @@ struct PrivacyVisitor<'a, 'tcx: 'a> {
in_foreign: bool, in_foreign: bool,
parents: NodeMap<ast::NodeId>, parents: NodeMap<ast::NodeId>,
external_exports: ExternalExports, external_exports: ExternalExports,
last_private_map: LastPrivateMap,
} }
enum PrivacyResult { enum PrivacyResult {
@ -730,7 +728,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
&format!("{} `{}`", tyname, name)) &format!("{} `{}`", tyname, name))
}; };
match self.last_private_map[path_id] { match self.tcx.last_private_map.borrow()[path_id] {
LastMod(AllPublic) => {}, LastMod(AllPublic) => {},
LastMod(DependsOn(def)) => { LastMod(DependsOn(def)) => {
self.report_error(ck_public(def)); self.report_error(ck_public(def));
@ -1500,8 +1498,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
pub fn check_crate(tcx: &ty::ctxt, pub fn check_crate(tcx: &ty::ctxt,
export_map: &def::ExportMap, export_map: &def::ExportMap,
external_exports: ExternalExports, external_exports: ExternalExports)
last_private_map: LastPrivateMap)
-> (ExportedItems, PublicItems) { -> (ExportedItems, PublicItems) {
let krate = tcx.map.krate(); let krate = tcx.map.krate();
@ -1519,7 +1516,6 @@ pub fn check_crate(tcx: &ty::ctxt,
tcx: tcx, tcx: tcx,
parents: visitor.parents, parents: visitor.parents,
external_exports: external_exports, external_exports: external_exports,
last_private_map: last_private_map,
}; };
visit::walk_crate(&mut visitor, krate); visit::walk_crate(&mut visitor, krate);

View file

@ -39,18 +39,16 @@ use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic};
use syntax::ast::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn}; use syntax::ast::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn};
use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
use syntax::ast::{MethodImplItem, Name, NamedField, NodeId}; use syntax::ast::{Name, NamedField, NodeId};
use syntax::ast::{PathListIdent, PathListMod, Public}; use syntax::ast::{PathListIdent, PathListMod, Public};
use syntax::ast::StmtDecl; use syntax::ast::StmtDecl;
use syntax::ast::StructVariantKind; use syntax::ast::StructVariantKind;
use syntax::ast::TupleVariantKind; use syntax::ast::TupleVariantKind;
use syntax::ast::TyObjectSum; use syntax::ast::UnnamedField;
use syntax::ast::{TypeImplItem, UnnamedField};
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::ast::{Visibility}; use syntax::ast::{Visibility};
use syntax::ast::TyPath;
use syntax::ast; use syntax::ast;
use syntax::ast_util::{self, PostExpansionMethod, local_def}; use syntax::ast_util::{self, local_def};
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
use syntax::parse::token::{self, special_idents}; use syntax::parse::token::{self, special_idents};
use syntax::codemap::{Span, DUMMY_SP}; use syntax::codemap::{Span, DUMMY_SP};
@ -177,12 +175,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
Some(TypeNS) Some(TypeNS)
} }
ForbidDuplicateTypesAndModules => { ForbidDuplicateTypesAndModules => {
match child.def_for_namespace(TypeNS) { if child.defined_in_namespace(TypeNS) {
None => {} duplicate_type = TypeError;
Some(_) if child.get_module_if_available()
.map(|m| m.kind.get()) ==
Some(ImplModuleKind) => {}
Some(_) => duplicate_type = TypeError
} }
Some(TypeNS) Some(TypeNS)
} }
@ -461,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); name_bindings.define_type(DefTy(local_def(item.id), true), sp, modifiers);
let parent_link = self.get_parent_link(parent, name); 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, name_bindings.set_module_kind(parent_link,
Some(local_def(item.id)), Some(local_def(item.id)),
EnumModuleKind, EnumModuleKind,
@ -513,133 +504,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
parent.clone() parent.clone()
} }
ItemImpl(_, _, _, None, ref ty, ref impl_items) => { ItemImpl(..) => parent.clone(),
// 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 = DefMethod(local_def(method.id),
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(item.id),
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(_, _) | ItemDefaultImpl(_, _) |
ItemImpl(_, _, _, Some(_), _, _) => parent.clone(),
ItemTrait(_, _, _, ref items) => { ItemTrait(_, _, _, ref items) => {
let name_bindings = let name_bindings =
@ -805,8 +671,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
let kind = match def { let kind = match def {
DefTy(_, true) => EnumModuleKind, DefTy(_, true) => EnumModuleKind,
DefTy(_, false) => TypeModuleKind, DefTy(_, false) | DefStruct(..) => TypeModuleKind,
DefStruct(..) => ImplModuleKind,
_ => NormalModuleKind _ => NormalModuleKind
}; };
@ -980,92 +845,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
} }
} }
} }
DlImpl(def) => { DlImpl(_) => {
match csearch::get_type_name_if_impl(&self.session.cstore, def) { debug!("(building reduced graph for external crate) \
None => {} ignoring impl");
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 => {}
}
}
}
} }
DlField => { DlField => {
debug!("(building reduced graph for external crate) \ debug!("(building reduced graph for external crate) \

View file

@ -514,7 +514,6 @@ enum ParentLink {
enum ModuleKind { enum ModuleKind {
NormalModuleKind, NormalModuleKind,
TraitModuleKind, TraitModuleKind,
ImplModuleKind,
EnumModuleKind, EnumModuleKind,
TypeModuleKind, TypeModuleKind,
AnonymousModuleKind, AnonymousModuleKind,
@ -1863,13 +1862,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match import_resolution.value_target { match import_resolution.value_target {
Some(ref target) if target.shadowable != Shadowable::Always => { Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref value) = *name_bindings.value_def.borrow() { if let Some(ref value) = *name_bindings.value_def.borrow() {
let msg = format!("import `{}` conflicts with value \ span_err!(self.session, import_span, E0255,
in this module", "import `{}` conflicts with value in this module",
&token::get_name(name)); &token::get_name(name));
span_err!(self.session, import_span, E0255, "{}", &msg[..]);
if let Some(span) = value.value_span { if let Some(span) = value.value_span {
self.session.span_note(span, self.session.span_note(span, "conflicting value here");
"conflicting value here");
} }
} }
} }
@ -1879,41 +1876,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match import_resolution.type_target { match import_resolution.type_target {
Some(ref target) if target.shadowable != Shadowable::Always => { Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref ty) = *name_bindings.type_def.borrow() { if let Some(ref ty) = *name_bindings.type_def.borrow() {
match ty.module_def { let (what, note) = if ty.module_def.is_some() {
None => { ("existing submodule", "note conflicting module here")
let msg = format!("import `{}` conflicts with type in \ } else {
this module", ("type in this module", "note conflicting type here")
&token::get_name(name)); };
span_err!(self.session, import_span, E0256, "{}", &msg[..]); span_err!(self.session, import_span, E0256,
"import `{}` conflicts with {}",
&token::get_name(name), what);
if let Some(span) = ty.type_span { if let Some(span) = ty.type_span {
self.session.span_note(span, self.session.span_note(span, note);
"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")
}
}
}
}
} }
} }
} }
@ -2267,7 +2239,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
return Failed(None); return Failed(None);
} }
TraitModuleKind | TraitModuleKind |
ImplModuleKind |
EnumModuleKind | EnumModuleKind |
TypeModuleKind | TypeModuleKind |
AnonymousModuleKind => { AnonymousModuleKind => {
@ -2365,7 +2336,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match new_module.kind.get() { match new_module.kind.get() {
NormalModuleKind => return Some(new_module), NormalModuleKind => return Some(new_module),
TraitModuleKind | TraitModuleKind |
ImplModuleKind |
EnumModuleKind | EnumModuleKind |
TypeModuleKind | TypeModuleKind |
AnonymousModuleKind => module_ = new_module, AnonymousModuleKind => module_ = new_module,
@ -2382,7 +2352,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match module_.kind.get() { match module_.kind.get() {
NormalModuleKind => return module_, NormalModuleKind => return module_,
TraitModuleKind | TraitModuleKind |
ImplModuleKind |
EnumModuleKind | EnumModuleKind |
TypeModuleKind | TypeModuleKind |
AnonymousModuleKind => { AnonymousModuleKind => {

View file

@ -15,6 +15,7 @@ use check::{FnCtxt};
use check::vtable; use check::vtable;
use check::vtable::select_new_fcx_obligations; use check::vtable::select_new_fcx_obligations;
use middle::def; use middle::def;
use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
use middle::subst; use middle::subst;
use middle::traits; use middle::traits;
use middle::ty::*; use middle::ty::*;
@ -309,16 +310,22 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
method_name: ast::Name, method_name: ast::Name,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
expr_id: ast::NodeId) expr_id: ast::NodeId)
-> Result<def::Def, MethodError> -> Result<(def::Def, LastPrivate), MethodError>
{ {
let mode = probe::Mode::Path; let mode = probe::Mode::Path;
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id)); let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
let def_id = pick.method_ty.def_id; let def_id = pick.method_ty.def_id;
let mut lp = LastMod(AllPublic);
let provenance = match pick.kind { let provenance = match pick.kind {
probe::InherentImplPick(impl_def_id) => def::FromImpl(impl_def_id), 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()) _ => def::FromTrait(pick.method_ty.container.id())
}; };
Ok(def::DefMethod(def_id, provenance)) Ok((def::DefMethod(def_id, provenance), lp))
} }

View file

@ -281,6 +281,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
ty::ty_closure(did, _, _) => { ty::ty_closure(did, _, _) => {
self.assemble_inherent_impl_candidates_for_type(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) => { ty::ty_param(p) => {
self.assemble_inherent_candidates_from_param(self_ty, p); self.assemble_inherent_candidates_from_param(self_ty, p);
} }

View file

@ -33,7 +33,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span, span: Span,
rcvr_ty: Ty<'tcx>, rcvr_ty: Ty<'tcx>,
method_name: ast::Name, method_name: ast::Name,
callee_expr: &ast::Expr, rcvr_expr: Option<&ast::Expr>,
error: MethodError) error: MethodError)
{ {
// avoid suggestions when we don't know what's going on. // 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 cx = fcx.tcx();
let method_ustring = method_name.user_string(cx); 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( fcx.type_error_message(
span, span,
|actual| { |actual| {
@ -68,11 +58,14 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
None); None);
// If the method has the name of a field, give a help note // If the method has the name of a field, give a help note
if is_field { 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, cx.sess.span_note(span,
&format!("use `(s.{0})(...)` if you meant to call the \ &format!("use `(s.{0})(...)` if you meant to call the \
function stored in the `{0}` field", method_ustring)); function stored in the `{0}` field", method_ustring));
} }
}
if static_sources.len() > 0 { if static_sources.len() > 0 {
fcx.tcx().sess.fileline_note( fcx.tcx().sess.fileline_note(
@ -82,7 +75,8 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
report_candidates(fcx, span, method_name, static_sources); 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) => { MethodError::Ambiguity(sources) => {
@ -93,15 +87,18 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} }
MethodError::ClosureAmbiguity(trait_def_id) => { MethodError::ClosureAmbiguity(trait_def_id) => {
fcx.sess().span_err( let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
span,
&*format!("the `{}` method from the `{}` trait cannot be explicitly \
invoked on this closure as we have not yet inferred what \ invoked on this closure as we have not yet inferred what \
kind of closure it is; use overloaded call notation instead \ kind of closure it is",
(e.g., `{}()`)",
method_name.user_string(fcx.tcx()), method_name.user_string(fcx.tcx()),
ty::item_path_str(fcx.tcx(), trait_def_id), ty::item_path_str(fcx.tcx(), trait_def_id));
pprust::expr_to_string(callee_expr))); 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, span: Span,
rcvr_ty: Ty<'tcx>, rcvr_ty: Ty<'tcx>,
method_name: ast::Name, method_name: ast::Name,
rcvr_expr: Option<&ast::Expr>,
valid_out_of_scope_traits: Vec<ast::DefId>) valid_out_of_scope_traits: Vec<ast::DefId>)
{ {
let tcx = fcx.tcx(); let tcx = fcx.tcx();
@ -184,7 +182,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
return 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 // there's no implemented traits, so lets suggest some traits to
// implement, by finding ones that have the method name, and are // 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`. /// autoderefs of `rcvr_ty`.
fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span, span: Span,
rcvr_ty: Ty<'tcx>) -> bool { rcvr_ty: Ty<'tcx>,
check::autoderef(fcx, span, rcvr_ty, None, rcvr_expr: Option<&ast::Expr>) -> bool {
check::UnresolvedTypeAction::Ignore, check::NoPreference, fn is_local(ty: Ty) -> bool {
|&: ty, _| { match ty.sty {
let is_local = match ty.sty {
ty::ty_enum(did, _) | ty::ty_struct(did, _) => ast_util::is_local(did), 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_trait(ref tr) => ast_util::is_local(tr.principal_def_id()),
ty::ty_param(_) => true, 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 // everything else (primitive types etc.) is effectively
// non-local (there are "edge" cases, e.g. (LocalType,), but // non-local (there are "edge" cases, e.g. (LocalType,), but
// the noise from these sort of types is usually just really // the noise from these sort of types is usually just really
// annoying, rather than any sort of help). // annoying, rather than any sort of help).
_ => false _ => 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 { } else {
None None
} }
}).2.unwrap_or(false) }).2.is_some()
} }
#[derive(Copy)] #[derive(Copy)]

View file

@ -91,6 +91,7 @@ use middle::infer;
use middle::mem_categorization as mc; use middle::mem_categorization as mc;
use middle::mem_categorization::McResult; use middle::mem_categorization::McResult;
use middle::pat_util::{self, pat_id_map}; use middle::pat_util::{self, pat_id_map};
use middle::privacy::{AllPublic, LastMod};
use middle::region::{self, CodeExtent}; use middle::region::{self, CodeExtent};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits; use middle::traits;
@ -2687,7 +2688,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
} }
Err(error) => { Err(error) => {
method::report_error(fcx, method_name.span, expr_t, 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.write_error(expr.id);
fcx.tcx().types.err fcx.tcx().types.err
} }
@ -3598,8 +3599,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
}; };
// Helpers to avoid keeping the RefCell borrow for too long. // Helpers to avoid keeping the RefCell borrow for too long.
let get_def = |&:| tcx.def_map.borrow().get(&id).cloned(); let get_def = || tcx.def_map.borrow().get(&id).cloned();
let get_partial_def = |&:| tcx.partial_def_map.borrow().get(&id).cloned(); let get_partial_def = || tcx.partial_def_map.borrow().get(&id).cloned();
if let Some(def) = get_def() { if let Some(def) = get_def() {
let (scheme, predicates) = let (scheme, predicates) =
@ -3621,10 +3622,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
let method_segment = path.segments.last().unwrap(); let method_segment = path.segments.last().unwrap();
let method_name = method_segment.identifier.name; let method_name = method_segment.identifier.name;
match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) { match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
Ok(def) => { Ok((def, lp)) => {
// Write back the new resolution. // Write back the new resolution.
tcx.def_map.borrow_mut().insert(id, def); tcx.def_map.borrow_mut().insert(id, def);
if let LastMod(AllPublic) = lp {
// Public method, don't change the last private entry.
} else {
tcx.last_private_map.borrow_mut().insert(id, lp);
}
let (scheme, predicates) = let (scheme, predicates) =
type_scheme_and_predicates_for_def(fcx, expr.span, def); type_scheme_and_predicates_for_def(fcx, expr.span, def);
instantiate_path(fcx, slice::ref_slice(method_segment), instantiate_path(fcx, slice::ref_slice(method_segment),
@ -3633,7 +3640,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
} }
Err(error) => { Err(error) => {
method::report_error(fcx, expr.span, ty, method::report_error(fcx, expr.span, ty,
method_name, expr, error); method_name, None, error);
fcx.write_error(id); fcx.write_error(id);
} }
} }
@ -4842,10 +4849,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} }
} }
if let Some(self_ty) = opt_self_ty { if let Some(self_ty) = opt_self_ty {
// `<T as Trait>::foo` shouldn't have resolved to a `Self`-less item. if type_defs.len(subst::SelfSpace) == 1 {
assert_eq!(type_defs.len(subst::SelfSpace), 1);
substs.types.push(subst::SelfSpace, self_ty); substs.types.push(subst::SelfSpace, self_ty);
} }
}
// Now we have to compare the types that the user *actually* // Now we have to compare the types that the user *actually*
// provided against the types that were *expected*. If the user // provided against the types that were *expected*. If the user

View file

@ -15,8 +15,8 @@ use middle::traits;
use middle::ty; use middle::ty;
use syntax::ast::{Item, ItemImpl}; use syntax::ast::{Item, ItemImpl};
use syntax::ast; use syntax::ast;
use syntax::ast_map;
use syntax::ast_util; use syntax::ast_util;
use syntax::codemap::Span;
use syntax::visit; use syntax::visit;
use util::ppaux::{Repr, UserString}; use util::ppaux::{Repr, UserString};
@ -30,9 +30,9 @@ struct OrphanChecker<'cx, 'tcx:'cx> {
} }
impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { 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 { 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 \ "cannot associate methods with a type outside the \
crate the type is defined in; define and implement \ crate the type is defined in; define and implement \
a trait or new type instead"); a trait or new type instead");
@ -41,7 +41,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
} }
impl<'cx, 'tcx,'v> visit::Visitor<'v> for 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); let def_id = ast_util::local_def(item.id);
match item.node { match item.node {
ast::ItemImpl(_, _, _, None, _, _) => { ast::ItemImpl(_, _, _, None, _, _) => {
@ -52,15 +52,13 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
match self_ty.sty { match self_ty.sty {
ty::ty_enum(def_id, _) | ty::ty_enum(def_id, _) |
ty::ty_struct(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) => { 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(..) => { ty::ty_uniq(..) => {
self.check_def_id(item.span, self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap());
self.tcx.lang_items.owned_box()
.unwrap());
} }
_ => { _ => {
span_err!(self.tcx.sess, item.span, E0118, span_err!(self.tcx.sess, item.span, E0118,

View file

@ -80,6 +80,7 @@ register_diagnostics! {
E0120, E0120,
E0121, E0121,
E0122, E0122,
E0123,
E0124, E0124,
E0127, E0127,
E0128, E0128,

View file

@ -43,7 +43,7 @@ fn foo<'a>() {
//~^ ERROR too many type parameters provided //~^ ERROR too many type parameters provided
let _ = S::<'a,isize>::new::<f64>(1, 1.0); let _ = S::<'a,isize>::new::<f64>(1, 1.0);
//~^ ERROR too many lifetime parameters provided //~^ ERROR wrong number of lifetime parameters
let _: S2 = Trait::new::<isize,f64>(1, 1.0); let _: S2 = Trait::new::<isize,f64>(1, 1.0);
//~^ ERROR too many type parameters provided //~^ ERROR too many type parameters provided

View file

@ -19,5 +19,5 @@ impl<A, B, C = (A, B)> Foo<A, B, C> {
fn main() { fn main() {
Foo::<isize>::new(); Foo::<isize>::new();
//~^ ERROR too few type parameters provided //~^ ERROR wrong number of type arguments
} }

View file

@ -21,5 +21,5 @@ impl<T, A = Heap> Vec<T, A> {
fn main() { fn main() {
Vec::<isize, Heap, bool>::new(); Vec::<isize, Heap, bool>::new();
//~^ ERROR too many type parameters provided //~^ ERROR wrong number of type arguments
} }

View file

@ -11,7 +11,7 @@
struct Foo; struct Foo;
impl Foo { impl Foo {
fn orange(&self){} 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() {} fn main() {}

View file

@ -29,7 +29,7 @@ impl Foo for *const BarTy {
baz(); baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`? //~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
a; 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; y;
//~^ ERROR: unresolved name `y`. Did you mean `self.y`? //~^ ERROR: unresolved name `y`. Did you mean `self.y`?
a; a;
//~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`? //~^ ERROR: unresolved name `a`
bah; bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`? //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
b; 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; y;
//~^ ERROR: unresolved name `y`. Did you mean `self.y`? //~^ ERROR: unresolved name `y`. Did you mean `self.y`?
a; a;
//~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`? //~^ ERROR: unresolved name `a`
bah; bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`? //~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
b; b;
//~^ ERROR: unresolved name `b`. Did you mean to call `self.b`? //~^ ERROR: unresolved name `b`
} }
} }

View file

@ -18,7 +18,7 @@ mod B {
use crate1::A::Foo; use crate1::A::Foo;
fn bar(f: Foo) { fn bar(f: Foo) {
Foo::foo(&f); Foo::foo(&f);
//~^ ERROR: function `foo` is private //~^ ERROR: method `foo` is private
} }
} }

View file

@ -36,7 +36,7 @@ impl Groom for cat {
shave(4); shave(4);
//~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`? //~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`?
purr(); 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() { fn purr_louder() {
static_method(); static_method();
//~^ ERROR: unresolved name `static_method`. Did you mean to call `cat::static_method` //~^ ERROR: unresolved name `static_method`
purr(); purr();
//~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`? //~^ ERROR: unresolved name `purr`
purr(); purr();
//~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`? //~^ ERROR: unresolved name `purr`
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) { fn purr(&self) {
grow_older(); grow_older();
//~^ ERROR: unresolved name `grow_older`. Did you mean to call `cat::grow_older` //~^ ERROR: unresolved name `grow_older`
shave(); shave();
//~^ ERROR: unresolved name `shave` //~^ ERROR: unresolved name `shave`
} }
@ -79,7 +79,7 @@ impl cat {
whiskers = 4; whiskers = 4;
//~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`? //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
purr_louder(); purr_louder();
//~^ ERROR: unresolved name `purr_louder`. Did you mean to call `cat::purr_louder` //~^ ERROR: unresolved name `purr_louder`
} }
} }

View file

@ -17,7 +17,7 @@ impl Foo {
Foo { baz: 0 }.bar(); Foo { baz: 0 }.bar();
} }
fn bar() { //~ ERROR duplicate definition of value `bar` fn bar() { //~ ERROR duplicate method in trait impl
} }
} }

View file

@ -29,7 +29,7 @@ impl S {
// Cause an error. It shouldn't have any macro backtrace frames. // Cause an error. It shouldn't have any macro backtrace frames.
fn bar(&self) { } fn bar(&self) { }
fn bar(&self) { } //~ ERROR duplicate definition fn bar(&self) { } //~ ERROR duplicate method
} }
fn main() { } fn main() { }

View file

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// FIXME(eddyb/UFCS) This should have a nicer error, but that's not possible just yet. impl<T> Option<T> {
impl<T> Option<T> { //~ ERROR use of undeclared type name `Option` //~^ ERROR cannot associate methods with a type outside the crate the type is defined in
pub fn foo(&self) { } pub fn foo(&self) { }
} }

View file

@ -11,7 +11,7 @@
use Trait::foo; use Trait::foo;
//~^ ERROR `foo` is not directly importable //~^ ERROR `foo` is not directly importable
use Foo::new; use Foo::new;
//~^ ERROR `new` is not directly importable //~^ ERROR unresolved import `Foo::new`. Not a module `Foo`
pub trait Trait { pub trait Trait {
fn foo(); fn foo();

View file

@ -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 // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
// //
@ -8,17 +8,17 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Test calling methods on an impl for a bare trait. This test checks trait impls mod foo {
// must be in the same module as the trait. pub struct Point {
pub x: i32,
mod Foo { pub y: i32,
trait T {}
}
mod Bar {
impl<'a> ::Foo::T+'a { //~ERROR: inherent implementations may only be implemented in the same
fn foo(&self) {}
} }
} }
fn main() {} impl foo::Point {
fn x(&self) -> i32 { self.x }
}
fn main() {
assert_eq!((foo::Point { x: 1, y: 3}).x(), 1);
}

View file

@ -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 // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
// //
@ -8,17 +8,16 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
mod foo { mod Foo {
pub struct Foo { trait Trait {
x: isize, fn foo(&self);
y: isize,
} }
} }
impl foo::Foo { mod Bar {
//~^ ERROR implementations may only be implemented in the same module impl<'a> ::Foo::Trait+'a {
fn bar() {} fn bar(&self) { self.foo() }
}
} }
fn main() {} fn main() {}