Skip to content

Commit 62d181f

Browse files
committed
Autoderef privacy for fields
1 parent d5a91e6 commit 62d181f

File tree

1 file changed

+48
-35
lines changed
  • src/librustc_typeck/check

1 file changed

+48
-35
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2938,25 +2938,26 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29382938
base: &'tcx hir::Expr,
29392939
field: &Spanned<ast::Name>) {
29402940
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2941-
let expr_t = structurally_resolved_type(fcx, expr.span,
2942-
fcx.expr_ty(base));
2943-
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2941+
let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
2942+
let mut private_candidate = None;
29442943
let (_, autoderefs, field_ty) = autoderef(fcx,
29452944
expr.span,
29462945
expr_t,
29472946
|| Some(base),
29482947
UnresolvedTypeAction::Error,
29492948
lvalue_pref,
29502949
|base_t, _| {
2951-
match base_t.sty {
2952-
ty::TyStruct(base_def, substs) => {
2953-
debug!("struct named {:?}", base_t);
2954-
base_def.struct_variant()
2955-
.find_field_named(field.node)
2956-
.map(|f| fcx.field_ty(expr.span, f, substs))
2950+
if let ty::TyStruct(base_def, substs) = base_t.sty {
2951+
debug!("struct named {:?}", base_t);
2952+
if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
2953+
let field_ty = fcx.field_ty(expr.span, field, substs);
2954+
if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) {
2955+
return Some(field_ty);
2956+
}
2957+
private_candidate = Some((base_def.did, field_ty));
29572958
}
2958-
_ => None
29592959
}
2960+
None
29602961
});
29612962
match field_ty {
29622963
Some(field_ty) => {
@@ -2967,12 +2968,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29672968
None => {}
29682969
}
29692970

2970-
if field.node == special_idents::invalid.name {
2971+
if let Some((did, field_ty)) = private_candidate {
2972+
let struct_path = fcx.tcx().item_path_str(did);
2973+
let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
2974+
fcx.tcx().sess.span_err(expr.span, &msg);
2975+
fcx.write_ty(expr.id, field_ty);
2976+
} else if field.node == special_idents::invalid.name {
29712977
fcx.write_error(expr.id);
2972-
return;
2973-
}
2974-
2975-
if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
2978+
} else if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
29762979
fcx.type_error_struct(field.span,
29772980
|actual| {
29782981
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>,
29832986
"maybe a `()` to call it is missing? \
29842987
If not, try an anonymous function")
29852988
.emit();
2989+
fcx.write_error(expr.id);
29862990
} else {
29872991
let mut err = fcx.type_error_struct(
29882992
expr.span,
@@ -2998,9 +3002,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29983002
suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
29993003
}
30003004
err.emit();
3005+
fcx.write_error(expr.id);
30013006
}
3002-
3003-
fcx.write_error(expr.id);
30043007
}
30053008

30063009
// displays hints about the closest matches in field names
@@ -3035,36 +3038,37 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
30353038
base: &'tcx hir::Expr,
30363039
idx: codemap::Spanned<usize>) {
30373040
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3038-
let expr_t = structurally_resolved_type(fcx, expr.span,
3039-
fcx.expr_ty(base));
3041+
let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
3042+
let mut private_candidate = None;
30403043
let mut tuple_like = false;
3041-
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
30423044
let (_, autoderefs, field_ty) = autoderef(fcx,
30433045
expr.span,
30443046
expr_t,
30453047
|| Some(base),
30463048
UnresolvedTypeAction::Error,
30473049
lvalue_pref,
30483050
|base_t, _| {
3049-
match base_t.sty {
3050-
ty::TyStruct(base_def, substs) => {
3051-
tuple_like = base_def.struct_variant().is_tuple_struct();
3052-
if tuple_like {
3053-
debug!("tuple struct named {:?}", base_t);
3054-
base_def.struct_variant()
3055-
.fields
3056-
.get(idx.node)
3057-
.map(|f| fcx.field_ty(expr.span, f, substs))
3058-
} else {
3059-
None
3060-
}
3061-
}
3051+
let (base_def, substs) = match base_t.sty {
3052+
ty::TyStruct(base_def, substs) => (base_def, substs),
30623053
ty::TyTuple(ref v) => {
30633054
tuple_like = true;
3064-
if idx.node < v.len() { Some(v[idx.node]) } else { None }
3055+
return if idx.node < v.len() { Some(v[idx.node]) } else { None }
30653056
}
3066-
_ => None
3057+
_ => return None,
3058+
};
3059+
3060+
tuple_like = base_def.struct_variant().is_tuple_struct();
3061+
if !tuple_like { return None }
3062+
3063+
debug!("tuple struct named {:?}", base_t);
3064+
if let Some(field) = base_def.struct_variant().fields.get(idx.node) {
3065+
let field_ty = fcx.field_ty(expr.span, field, substs);
3066+
if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) {
3067+
return Some(field_ty);
3068+
}
3069+
private_candidate = Some((base_def.did, field_ty));
30673070
}
3071+
None
30683072
});
30693073
match field_ty {
30703074
Some(field_ty) => {
@@ -3074,6 +3078,15 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
30743078
}
30753079
None => {}
30763080
}
3081+
3082+
if let Some((did, field_ty)) = private_candidate {
3083+
let struct_path = fcx.tcx().item_path_str(did);
3084+
let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
3085+
fcx.tcx().sess.span_err(expr.span, &msg);
3086+
fcx.write_ty(expr.id, field_ty);
3087+
return;
3088+
}
3089+
30773090
fcx.type_error_message(
30783091
expr.span,
30793092
|actual| {

0 commit comments

Comments
 (0)