Autoderef privacy for fields

This commit is contained in:
Jeffrey Seyfried 2016-02-24 10:58:35 +00:00
parent d5a91e6958
commit 62d181f474
1 changed files with 48 additions and 35 deletions

View File

@ -2938,9 +2938,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
base: &'tcx hir::Expr,
field: &Spanned<ast::Name>) {
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
let mut private_candidate = None;
let (_, autoderefs, field_ty) = autoderef(fcx,
expr.span,
expr_t,
@ -2948,15 +2947,17 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error,
lvalue_pref,
|base_t, _| {
match base_t.sty {
ty::TyStruct(base_def, substs) => {
debug!("struct named {:?}", base_t);
base_def.struct_variant()
.find_field_named(field.node)
.map(|f| fcx.field_ty(expr.span, f, substs))
if let ty::TyStruct(base_def, substs) = base_t.sty {
debug!("struct named {:?}", base_t);
if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
let field_ty = fcx.field_ty(expr.span, field, substs);
if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) {
return Some(field_ty);
}
private_candidate = Some((base_def.did, field_ty));
}
_ => None
}
None
});
match field_ty {
Some(field_ty) => {
@ -2967,12 +2968,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
None => {}
}
if field.node == special_idents::invalid.name {
if let Some((did, field_ty)) = private_candidate {
let struct_path = fcx.tcx().item_path_str(did);
let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
fcx.tcx().sess.span_err(expr.span, &msg);
fcx.write_ty(expr.id, field_ty);
} else if field.node == special_idents::invalid.name {
fcx.write_error(expr.id);
return;
}
if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
} else if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
fcx.type_error_struct(field.span,
|actual| {
format!("attempted to take value of method `{}` on type \
@ -2983,6 +2986,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
"maybe a `()` to call it is missing? \
If not, try an anonymous function")
.emit();
fcx.write_error(expr.id);
} else {
let mut err = fcx.type_error_struct(
expr.span,
@ -2998,9 +3002,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
}
err.emit();
fcx.write_error(expr.id);
}
fcx.write_error(expr.id);
}
// displays hints about the closest matches in field names
@ -3035,10 +3038,9 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
base: &'tcx hir::Expr,
idx: codemap::Spanned<usize>) {
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
let mut private_candidate = None;
let mut tuple_like = false;
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
let (_, autoderefs, field_ty) = autoderef(fcx,
expr.span,
expr_t,
@ -3046,25 +3048,27 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error,
lvalue_pref,
|base_t, _| {
match base_t.sty {
ty::TyStruct(base_def, substs) => {
tuple_like = base_def.struct_variant().is_tuple_struct();
if tuple_like {
debug!("tuple struct named {:?}", base_t);
base_def.struct_variant()
.fields
.get(idx.node)
.map(|f| fcx.field_ty(expr.span, f, substs))
} else {
None
}
}
let (base_def, substs) = match base_t.sty {
ty::TyStruct(base_def, substs) => (base_def, substs),
ty::TyTuple(ref v) => {
tuple_like = true;
if idx.node < v.len() { Some(v[idx.node]) } else { None }
return if idx.node < v.len() { Some(v[idx.node]) } else { None }
}
_ => None
_ => return None,
};
tuple_like = base_def.struct_variant().is_tuple_struct();
if !tuple_like { return None }
debug!("tuple struct named {:?}", base_t);
if let Some(field) = base_def.struct_variant().fields.get(idx.node) {
let field_ty = fcx.field_ty(expr.span, field, substs);
if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) {
return Some(field_ty);
}
private_candidate = Some((base_def.did, field_ty));
}
None
});
match field_ty {
Some(field_ty) => {
@ -3074,6 +3078,15 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
None => {}
}
if let Some((did, field_ty)) = private_candidate {
let struct_path = fcx.tcx().item_path_str(did);
let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
fcx.tcx().sess.span_err(expr.span, &msg);
fcx.write_ty(expr.id, field_ty);
return;
}
fcx.type_error_message(
expr.span,
|actual| {