mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
rustc_resolve: don't handle impl items as if they were modules.
This commit is contained in:
parent
6700166442
commit
06f362aeb3
@ -51,6 +51,7 @@ use middle::dependency_format;
|
||||
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
|
||||
use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem};
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::privacy::LastPrivateMap;
|
||||
use middle::region;
|
||||
use middle::resolve_lifetime;
|
||||
use middle::infer;
|
||||
@ -683,6 +684,7 @@ pub struct ctxt<'tcx> {
|
||||
pub sess: Session,
|
||||
pub def_map: DefMap,
|
||||
pub partial_def_map: PartialDefMap,
|
||||
pub last_private_map: RefCell<LastPrivateMap>,
|
||||
|
||||
pub named_region_map: resolve_lifetime::NamedRegionMap,
|
||||
|
||||
@ -2426,6 +2428,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
||||
arenas: &'tcx CtxtArenas<'tcx>,
|
||||
def_map: DefMap,
|
||||
partial_def_map: PartialDefMap,
|
||||
last_private_map: LastPrivateMap,
|
||||
named_region_map: resolve_lifetime::NamedRegionMap,
|
||||
map: ast_map::Map<'tcx>,
|
||||
freevars: RefCell<FreevarMap>,
|
||||
@ -2449,6 +2452,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
||||
sess: s,
|
||||
def_map: def_map,
|
||||
partial_def_map: partial_def_map,
|
||||
last_private_map: RefCell::new(last_private_map),
|
||||
region_maps: region_maps,
|
||||
node_types: RefCell::new(FnvHashMap()),
|
||||
item_substs: RefCell::new(NodeMap()),
|
||||
|
@ -609,6 +609,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
|
||||
arenas,
|
||||
def_map,
|
||||
partial_def_map,
|
||||
last_private_map,
|
||||
named_region_map,
|
||||
ast_map,
|
||||
freevars,
|
||||
@ -622,10 +623,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", (), |_|
|
||||
|
@ -38,8 +38,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};
|
||||
@ -379,7 +378,6 @@ struct PrivacyVisitor<'a, 'tcx: 'a> {
|
||||
in_foreign: bool,
|
||||
parents: NodeMap<ast::NodeId>,
|
||||
external_exports: ExternalExports,
|
||||
last_private_map: LastPrivateMap,
|
||||
}
|
||||
|
||||
enum PrivacyResult {
|
||||
@ -730,7 +728,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
||||
&format!("{} `{}`", tyname, name))
|
||||
};
|
||||
|
||||
match self.last_private_map[path_id] {
|
||||
match self.tcx.last_private_map.borrow()[path_id] {
|
||||
LastMod(AllPublic) => {},
|
||||
LastMod(DependsOn(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,
|
||||
export_map: &def::ExportMap,
|
||||
external_exports: ExternalExports,
|
||||
last_private_map: LastPrivateMap)
|
||||
external_exports: ExternalExports)
|
||||
-> (ExportedItems, PublicItems) {
|
||||
let krate = tcx.map.krate();
|
||||
|
||||
@ -1519,7 +1516,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);
|
||||
|
||||
|
@ -39,18 +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::{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};
|
||||
@ -177,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)
|
||||
}
|
||||
@ -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);
|
||||
|
||||
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,
|
||||
@ -513,133 +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 = 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()
|
||||
}
|
||||
|
||||
ItemImpl(..) => parent.clone(),
|
||||
ItemDefaultImpl(_, _) |
|
||||
ItemImpl(_, _, _, Some(_), _, _) => parent.clone(),
|
||||
|
||||
ItemTrait(_, _, _, ref items) => {
|
||||
let name_bindings =
|
||||
@ -805,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
|
||||
};
|
||||
|
||||
@ -980,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) \
|
||||
|
@ -514,7 +514,6 @@ enum ParentLink {
|
||||
enum ModuleKind {
|
||||
NormalModuleKind,
|
||||
TraitModuleKind,
|
||||
ImplModuleKind,
|
||||
EnumModuleKind,
|
||||
TypeModuleKind,
|
||||
AnonymousModuleKind,
|
||||
@ -1863,13 +1862,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1879,41 +1876,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2267,7 +2239,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
return Failed(None);
|
||||
}
|
||||
TraitModuleKind |
|
||||
ImplModuleKind |
|
||||
EnumModuleKind |
|
||||
TypeModuleKind |
|
||||
AnonymousModuleKind => {
|
||||
@ -2365,7 +2336,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,
|
||||
@ -2382,7 +2352,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
match module_.kind.get() {
|
||||
NormalModuleKind => return module_,
|
||||
TraitModuleKind |
|
||||
ImplModuleKind |
|
||||
EnumModuleKind |
|
||||
TypeModuleKind |
|
||||
AnonymousModuleKind => {
|
||||
|
@ -15,6 +15,7 @@ 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::*;
|
||||
@ -309,16 +310,22 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
method_name: ast::Name,
|
||||
self_ty: Ty<'tcx>,
|
||||
expr_id: ast::NodeId)
|
||||
-> Result<def::Def, MethodError>
|
||||
-> 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) => 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())
|
||||
};
|
||||
Ok(def::DefMethod(def_id, provenance))
|
||||
Ok((def::DefMethod(def_id, provenance), lp))
|
||||
}
|
||||
|
||||
|
||||
|
@ -281,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);
|
||||
}
|
||||
|
@ -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<ast::DefId>)
|
||||
{
|
||||
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)]
|
||||
|
@ -91,6 +91,7 @@ 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;
|
||||
@ -2687,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
|
||||
}
|
||||
@ -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.
|
||||
let get_def = |&:| tcx.def_map.borrow().get(&id).cloned();
|
||||
let get_partial_def = |&:| tcx.partial_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();
|
||||
|
||||
if let Some(def) = get_def() {
|
||||
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_name = method_segment.identifier.name;
|
||||
match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
|
||||
Ok(def) => {
|
||||
Ok((def, lp)) => {
|
||||
// Write back the new resolution.
|
||||
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) =
|
||||
type_scheme_and_predicates_for_def(fcx, expr.span, def);
|
||||
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) => {
|
||||
method::report_error(fcx, expr.span, ty,
|
||||
method_name, expr, error);
|
||||
method_name, None, error);
|
||||
fcx.write_error(id);
|
||||
}
|
||||
}
|
||||
@ -4842,9 +4849,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
if let Some(self_ty) = opt_self_ty {
|
||||
// `<T as Trait>::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*
|
||||
|
@ -15,8 +15,8 @@ use middle::traits;
|
||||
use middle::ty;
|
||||
use syntax::ast::{Item, ItemImpl};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::visit;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
@ -30,9 +30,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 +41,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 +52,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,
|
||||
|
@ -80,6 +80,7 @@ register_diagnostics! {
|
||||
E0120,
|
||||
E0121,
|
||||
E0122,
|
||||
E0123,
|
||||
E0124,
|
||||
E0127,
|
||||
E0128,
|
||||
|
@ -43,7 +43,7 @@ fn foo<'a>() {
|
||||
//~^ ERROR too many type parameters provided
|
||||
|
||||
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);
|
||||
//~^ ERROR too many type parameters provided
|
||||
|
@ -19,5 +19,5 @@ impl<A, B, C = (A, B)> Foo<A, B, C> {
|
||||
|
||||
fn main() {
|
||||
Foo::<isize>::new();
|
||||
//~^ ERROR too few type parameters provided
|
||||
//~^ ERROR wrong number of type arguments
|
||||
}
|
||||
|
@ -21,5 +21,5 @@ impl<T, A = Heap> Vec<T, A> {
|
||||
|
||||
fn main() {
|
||||
Vec::<isize, Heap, bool>::new();
|
||||
//~^ ERROR too many type parameters provided
|
||||
//~^ ERROR wrong number of type arguments
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() { }
|
||||
|
@ -8,8 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// 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> { //~ ERROR use of undeclared type name `Option`
|
||||
impl<T> Option<T> {
|
||||
//~^ ERROR cannot associate methods with a type outside the crate the type is defined in
|
||||
pub fn foo(&self) { }
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
@ -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,
|
||||
mod Foo {
|
||||
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() {}
|
||||
|
Loading…
Reference in New Issue
Block a user