Autoderef privacy for methods

This commit is contained in:
Jeffrey Seyfried 2016-02-25 02:11:29 +00:00
parent 62d181f474
commit 6f16c5c81f
4 changed files with 46 additions and 14 deletions

View File

@ -43,6 +43,9 @@ pub enum MethodError<'tcx> {
// Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
ClosureAmbiguity(/* DefId of fn trait */ DefId),
// Found an applicable method, but it is not visible.
PrivateMatch(Def),
}
// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
@ -90,6 +93,7 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Err(ClosureAmbiguity(..)) => true,
Err(PrivateMatch(..)) => true,
}
}

View File

@ -16,6 +16,7 @@ use super::suggest;
use check;
use check::{FnCtxt, UnresolvedTypeAction};
use middle::def_id::DefId;
use middle::def::Def;
use rustc::ty::subst;
use rustc::ty::subst::Subst;
use rustc::traits;
@ -47,6 +48,9 @@ struct ProbeContext<'a, 'tcx:'a> {
/// used for error reporting
static_candidates: Vec<CandidateSource>,
/// Some(candidate) if there is a private candidate
private_candidate: Option<Def>,
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
/// for error reporting
unsatisfied_predicates: Vec<TraitRef<'tcx>>
@ -247,6 +251,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
steps: Rc::new(steps),
opt_simplified_steps: opt_simplified_steps,
static_candidates: Vec::new(),
private_candidate: None,
unsatisfied_predicates: Vec::new(),
}
}
@ -256,6 +261,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
self.extension_candidates.clear();
self.impl_dups.clear();
self.static_candidates.clear();
self.private_candidate = None;
}
fn tcx(&self) -> &'a TyCtxt<'tcx> {
@ -407,6 +413,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
return self.record_static_candidate(ImplSource(impl_def_id));
}
if item.vis() != hir::Public && !self.fcx.private_item_is_visible(item.def_id()) {
self.private_candidate = Some(item.def());
return
}
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
let impl_ty = impl_ty.subst(self.tcx(), &impl_substs);
@ -846,6 +857,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
}
let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
let private_candidate = mem::replace(&mut self.private_candidate, None);
let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]);
// things failed, so lets look at all traits, for diagnostic purposes now:
@ -879,9 +891,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
// this error only occurs when assembling candidates
tcx.sess.span_bug(span, "encountered ClosureAmbiguity from pick_core");
}
None => vec![],
_ => vec![],
};
if let Some(def) = private_candidate {
return Err(MethodError::PrivateMatch(def));
}
Err(MethodError::NoMatch(NoMatchData::new(static_candidates, unsatisfied_predicates,
out_of_scope_traits, self.mode)))
}

View File

@ -91,7 +91,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
unsatisfied_predicates,
out_of_scope_traits,
mode }) => {
mode, .. }) => {
let cx = fcx.tcx();
let mut err = fcx.type_error_struct(
@ -208,6 +208,11 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
};
fcx.sess().span_err(span, &msg);
}
MethodError::PrivateMatch(def) => {
let msg = format!("{} `{}` is private", def.kind_name(), item_name);
fcx.tcx().sess.span_err(span, &msg);
}
}
fn report_candidates(fcx: &FnCtxt,

View File

@ -3757,23 +3757,30 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
&ty_segments[base_ty_end..]);
let item_segment = path.segments.last().unwrap();
let item_name = item_segment.identifier.name;
match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
Ok(def) => {
// Write back the new resolution.
fcx.ccx.tcx.def_map.borrow_mut()
.insert(node_id, def::PathResolution {
base_def: def,
depth: 0
});
Some((Some(ty), slice::ref_slice(item_segment), def))
}
let def = match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
Ok(def) => Some(def),
Err(error) => {
let def = match error {
method::MethodError::PrivateMatch(def) => Some(def),
_ => None,
};
if item_name != special_idents::invalid.name {
method::report_error(fcx, span, ty, item_name, None, error);
}
fcx.write_error(node_id);
None
def
}
};
if let Some(def) = def {
// Write back the new resolution.
fcx.ccx.tcx.def_map.borrow_mut().insert(node_id, def::PathResolution {
base_def: def,
depth: 0,
});
Some((Some(ty), slice::ref_slice(item_segment), def))
} else {
fcx.write_error(node_id);
None
}
}
}