diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index c5b3d7065fa92..85bcc2745254d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1214,6 +1214,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_predicates, ) }; + if let SelfSource::MethodCall(rcvr_expr) = source { + self.err_ctxt().note_field_shadowed_by_private_candidate( + &mut err, + rcvr_expr.hir_id, + self.param_env, + ); + } self.set_label_for_method_error( &mut err, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index cf61728f7c2a3..f21db0bf85550 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -249,6 +249,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_ty_var, Some(lhs_expr), |err, ty| { + self.err_ctxt().note_field_shadowed_by_private_candidate( + err, + rhs_expr.hir_id, + self.param_env, + ); if let Op::BinOp(binop) = op && binop.node == hir::BinOpKind::Eq { @@ -331,6 +336,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}` on type `{}`", s, lhs_ty_str), ); + let err_ctxt = self.err_ctxt(); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + lhs_expr.hir_id, + self.param_env, + ); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + rhs_expr.hir_id, + self.param_env, + ); self.note_unmet_impls_on_type(&mut err, &errors, false); (err, None) } @@ -391,6 +407,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(lhs_expr.span, lhs_ty_str.clone()); err.span_label(rhs_expr.span, rhs_ty_str); } + let err_ctxt = self.err_ctxt(); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + lhs_expr.hir_id, + self.param_env, + ); + err_ctxt.note_field_shadowed_by_private_candidate( + &mut err, + rhs_expr.hir_id, + self.param_env, + ); let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty); self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive); (err, output_def_id) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index d9ea2e0057895..f7486a23bf731 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1528,6 +1528,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { label_or_note(span, terr.to_string(self.tcx)); } + if let Some(param_env) = param_env { + self.note_field_shadowed_by_private_candidate_in_cause(diag, cause, param_env); + } + if self.check_and_note_conflicting_crates(diag, terr) { return; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d0358b03af197..3ff08bbaf9dc2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -559,6 +559,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } + self.note_field_shadowed_by_private_candidate_in_cause( + &mut err, + &obligation.cause, + obligation.param_env, + ); self.try_to_add_help_message( &root_obligation, &obligation, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2d9574ea8c546..4912d5f4582e7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -22,8 +22,10 @@ use rustc_hir::{ expr_needs_parens, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::traits::ImplSource; use rustc_middle::middle::privacy::Level; use rustc_middle::traits::IsConstable; +use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::{ PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _, @@ -49,7 +51,7 @@ use crate::error_reporting::TypeErrCtxt; use crate::errors; use crate::infer::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt}; +use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt, SelectionContext}; #[derive(Debug)] pub enum CoroutineInteriorOrUpvar { @@ -242,6 +244,213 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( } impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn note_field_shadowed_by_private_candidate_in_cause( + &self, + err: &mut Diag<'_>, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) { + let mut hir_ids = FxHashSet::default(); + // Walk the parent chain so we can recover + // the source expression from whichever layer carries them. + let mut next_code = Some(cause.code()); + while let Some(cause_code) = next_code { + match cause_code { + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => { + hir_ids.insert(*lhs_hir_id); + hir_ids.insert(*rhs_hir_id); + } + ObligationCauseCode::FunctionArg { arg_hir_id, .. } + | ObligationCauseCode::ReturnValue(arg_hir_id) + | ObligationCauseCode::AwaitableExpr(arg_hir_id) + | ObligationCauseCode::BlockTailExpression(arg_hir_id, _) + | ObligationCauseCode::UnOp { hir_id: arg_hir_id } => { + hir_ids.insert(*arg_hir_id); + } + ObligationCauseCode::OpaqueReturnType(Some((_, hir_id))) => { + hir_ids.insert(*hir_id); + } + _ => {} + } + next_code = cause_code.parent(); + } + + if !cause.span.is_dummy() + && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_id) + { + let mut expr_finder = FindExprBySpan::new(cause.span, self.tcx); + expr_finder.visit_body(body); + if let Some(expr) = expr_finder.result { + hir_ids.insert(expr.hir_id); + } + } + + // we will sort immediately by source order before emitting any diagnostics + #[allow(rustc::potential_query_instability)] + let mut hir_ids: Vec<_> = hir_ids.into_iter().collect(); + let source_map = self.tcx.sess.source_map(); + hir_ids.sort_by_cached_key(|hir_id| { + let span = self.tcx.hir_span(*hir_id); + let lo = source_map.lookup_byte_offset(span.lo()); + let hi = source_map.lookup_byte_offset(span.hi()); + (lo.sf.name.prefer_remapped_unconditionally().to_string(), lo.pos.0, hi.pos.0) + }); + + for hir_id in hir_ids { + self.note_field_shadowed_by_private_candidate(err, hir_id, param_env); + } + } + + pub fn note_field_shadowed_by_private_candidate( + &self, + err: &mut Diag<'_>, + hir_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + ) { + let Some(typeck_results) = &self.typeck_results else { + return; + }; + let Node::Expr(expr) = self.tcx.hir_node(hir_id) else { + return; + }; + let hir::ExprKind::Field(base_expr, field_ident) = expr.kind else { + return; + }; + + let Some(base_ty) = typeck_results.expr_ty_opt(base_expr) else { + return; + }; + let base_ty = self.resolve_vars_if_possible(base_ty); + if base_ty.references_error() { + return; + } + + let fn_body_hir_id = self.tcx.local_def_id_to_hir_id(typeck_results.hir_owner.def_id); + let mut private_candidate: Option<(Ty<'tcx>, Ty<'tcx>, Span)> = None; + + for (deref_base_ty, _) in (self.autoderef_steps)(base_ty) { + let ty::Adt(base_def, args) = deref_base_ty.kind() else { + continue; + }; + + if base_def.is_enum() { + continue; + } + + let (adjusted_ident, def_scope) = + self.tcx.adjust_ident_and_get_scope(field_ident, base_def.did(), fn_body_hir_id); + + let Some((_, field_def)) = + base_def.non_enum_variant().fields.iter_enumerated().find(|(_, field)| { + field.ident(self.tcx).normalize_to_macros_2_0() == adjusted_ident + }) + else { + continue; + }; + let field_span = self + .tcx + .def_ident_span(field_def.did) + .unwrap_or_else(|| self.tcx.def_span(field_def.did)); + + if field_def.vis.is_accessible_from(def_scope, self.tcx) { + let accessible_field_ty = field_def.ty(self.tcx, args); + if let Some((private_base_ty, private_field_ty, private_field_span)) = + private_candidate + && !self.can_eq(param_env, private_field_ty, accessible_field_ty) + { + let private_struct_span = match private_base_ty.kind() { + ty::Adt(private_base_def, _) => self + .tcx + .def_ident_span(private_base_def.did()) + .unwrap_or_else(|| self.tcx.def_span(private_base_def.did())), + _ => DUMMY_SP, + }; + let accessible_struct_span = self + .tcx + .def_ident_span(base_def.did()) + .unwrap_or_else(|| self.tcx.def_span(base_def.did())); + let deref_impl_span = (typeck_results + .expr_adjustments(base_expr) + .iter() + .filter(|adj| { + matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_))) + }) + .count() + == 1) + .then(|| { + self.probe(|_| { + let deref_trait_did = + self.tcx.require_lang_item(LangItem::Deref, DUMMY_SP); + let trait_ref = + ty::TraitRef::new(self.tcx, deref_trait_did, [private_base_ty]); + let obligation: Obligation<'tcx, ty::Predicate<'tcx>> = + Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + trait_ref, + ); + let Ok(Some(ImplSource::UserDefined(impl_data))) = + SelectionContext::new(self) + .select(&obligation.with(self.tcx, trait_ref)) + else { + return None; + }; + Some(self.tcx.def_span(impl_data.impl_def_id)) + }) + }) + .flatten(); + + let mut note_spans: MultiSpan = private_struct_span.into(); + if private_struct_span != DUMMY_SP { + note_spans.push_span_label(private_struct_span, "in this struct"); + } + if private_field_span != DUMMY_SP { + note_spans.push_span_label( + private_field_span, + "if this field wasn't private, it would be accessible", + ); + } + if accessible_struct_span != DUMMY_SP { + note_spans.push_span_label( + accessible_struct_span, + "this struct is accessible through auto-deref", + ); + } + if field_span != DUMMY_SP { + note_spans + .push_span_label(field_span, "this is the field that was accessed"); + } + if let Some(deref_impl_span) = deref_impl_span + && deref_impl_span != DUMMY_SP + { + note_spans.push_span_label( + deref_impl_span, + "the field was accessed through this `Deref`", + ); + } + + err.span_note( + note_spans, + format!( + "there is a field `{field_ident}` on `{private_base_ty}` with type `{private_field_ty}` but it is private; `{field_ident}` from `{deref_base_ty}` was accessed through auto-deref instead" + ), + ); + } + + // we finally get to the accessible field, + // so we can return early without checking the rest of the autoderef candidates + return; + } + + private_candidate.get_or_insert(( + deref_base_ty, + field_def.ty(self.tcx, args), + field_span, + )); + } + } + pub fn suggest_restricting_param_bound( &self, err: &mut Diag<'_>, diff --git a/tests/ui/privacy/private-field-deref-confusion-issue-149546.rs b/tests/ui/privacy/private-field-deref-confusion-issue-149546.rs new file mode 100644 index 0000000000000..ec26c879d4eb3 --- /dev/null +++ b/tests/ui/privacy/private-field-deref-confusion-issue-149546.rs @@ -0,0 +1,88 @@ +// Field lookup still resolves to the public field on the Deref target, but +// follow-up diagnostics should explain that the original type has a same-named +// private field with a different type. +//@ dont-require-annotations: ERROR + +mod structs { + pub struct A { + field: usize, + b: B, + } + + pub struct B { + pub field: bool, + } + + impl std::ops::Deref for A { + type Target = B; + + fn deref(&self) -> &Self::Target { + &self.b + } + } +} + +use structs::A; + +fn takes_usize(_: usize) {} + +trait Marker {} + +impl Marker for usize {} + +struct Wrapper(i32); + +impl std::ops::Add for Wrapper { + type Output = (); + + fn add(self, _: T) {} +} + +fn by_value(a: A) { + a.field + 5; +} + +fn by_ref(a: &A) { + a.field + 5; +} + +fn rhs_by_value(a: A) { + 5 + a.field; +} + +fn rhs_by_ref(a: &A) { + 5 + a.field; +} + +fn rhs_assign_op_by_value(a: A) { + let mut n = 5; + n += a.field; +} + +fn rhs_assign_op_by_ref(a: &A) { + let mut n = 5; + n += a.field; +} + +fn rhs_nested_obligation(a: A) { + Wrapper(5) + a.field; +} + +fn method_call(a: A) { + a.field.count_ones(); +} + +fn type_mismatch(a: A) { + let value: usize = a.field; + eprintln!("value: {value}"); +} + +fn function_arg(a: A) { + takes_usize(a.field); +} + +fn return_value(a: &A) -> usize { + a.field +} + +fn main() {} diff --git a/tests/ui/privacy/private-field-deref-confusion-issue-149546.stderr b/tests/ui/privacy/private-field-deref-confusion-issue-149546.stderr new file mode 100644 index 0000000000000..9f2bb523913c8 --- /dev/null +++ b/tests/ui/privacy/private-field-deref-confusion-issue-149546.stderr @@ -0,0 +1,317 @@ +error[E0369]: cannot add `{integer}` to `bool` + --> $DIR/private-field-deref-confusion-issue-149546.rs:42:13 + | +LL | a.field + 5; + | ------- ^ - {integer} + | | + | bool + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0369]: cannot add `{integer}` to `bool` + --> $DIR/private-field-deref-confusion-issue-149546.rs:46:13 + | +LL | a.field + 5; + | ------- ^ - {integer} + | | + | bool + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0277]: cannot add `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:50:7 + | +LL | 5 + a.field; + | ^ no implementation for `{integer} + bool` + | + = help: the trait `Add` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `Add`: + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` + and 56 others + +error[E0277]: cannot add `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:54:7 + | +LL | 5 + a.field; + | ^ no implementation for `{integer} + bool` + | + = help: the trait `Add` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `Add`: + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` + and 56 others + +error[E0277]: cannot add-assign `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:59:7 + | +LL | n += a.field; + | ^^ no implementation for `{integer} += bool` + | + = help: the trait `AddAssign` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `AddAssign`: + `f128` implements `AddAssign<&f128>` + `f128` implements `AddAssign` + `f16` implements `AddAssign<&f16>` + `f16` implements `AddAssign` + `f32` implements `AddAssign<&f32>` + `f32` implements `AddAssign` + `f64` implements `AddAssign<&f64>` + `f64` implements `AddAssign` + and 24 others + +error[E0277]: cannot add-assign `bool` to `{integer}` + --> $DIR/private-field-deref-confusion-issue-149546.rs:64:7 + | +LL | n += a.field; + | ^^ no implementation for `{integer} += bool` + | + = help: the trait `AddAssign` is not implemented for `{integer}` +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + = help: the following other types implement trait `AddAssign`: + `f128` implements `AddAssign<&f128>` + `f128` implements `AddAssign` + `f16` implements `AddAssign<&f16>` + `f16` implements `AddAssign` + `f32` implements `AddAssign<&f32>` + `f32` implements `AddAssign` + `f64` implements `AddAssign<&f64>` + `f64` implements `AddAssign` + and 24 others + +error[E0277]: the trait bound `bool: Marker` is not satisfied + --> $DIR/private-field-deref-confusion-issue-149546.rs:68:16 + | +LL | Wrapper(5) + a.field; + | ^ the trait `Marker` is not implemented for `bool` + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` +help: the trait `Marker` is implemented for `usize` + --> $DIR/private-field-deref-confusion-issue-149546.rs:31:1 + | +LL | impl Marker for usize {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: required for `Wrapper` to implement `Add` + --> $DIR/private-field-deref-confusion-issue-149546.rs:35:17 + | +LL | impl std::ops::Add for Wrapper { + | ------ ^^^^^^^^^^^^^^^^ ^^^^^^^ + | | + | unsatisfied trait bound introduced here + +error[E0599]: no method named `count_ones` found for type `bool` in the current scope + --> $DIR/private-field-deref-confusion-issue-149546.rs:72:13 + | +LL | a.field.count_ones(); + | ^^^^^^^^^^ method not found in `bool` + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0308]: mismatched types + --> $DIR/private-field-deref-confusion-issue-149546.rs:76:24 + | +LL | let value: usize = a.field; + | ----- ^^^^^^^ expected `usize`, found `bool` + | | + | expected due to this + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error[E0308]: mismatched types + --> $DIR/private-field-deref-confusion-issue-149546.rs:81:17 + | +LL | takes_usize(a.field); + | ----------- ^^^^^^^ expected `usize`, found `bool` + | | + | arguments to this function are incorrect + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` +note: function defined here + --> $DIR/private-field-deref-confusion-issue-149546.rs:27:4 + | +LL | fn takes_usize(_: usize) {} + | ^^^^^^^^^^^ -------- + +error[E0308]: mismatched types + --> $DIR/private-field-deref-confusion-issue-149546.rs:85:5 + | +LL | fn return_value(a: &A) -> usize { + | ----- expected `usize` because of return type +LL | a.field + | ^^^^^^^ expected `usize`, found `bool` + | +note: there is a field `field` on `A` with type `usize` but it is private; `field` from `B` was accessed through auto-deref instead + --> $DIR/private-field-deref-confusion-issue-149546.rs:7:16 + | +LL | pub struct A { + | ^ in this struct +LL | field: usize, + | ----- if this field wasn't private, it would be accessible +... +LL | pub struct B { + | - this struct is accessible through auto-deref +LL | pub field: bool, + | ----- this is the field that was accessed +... +LL | impl std::ops::Deref for A { + | -------------------------- the field was accessed through this `Deref` + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0277, E0308, E0369, E0599. +For more information about an error, try `rustc --explain E0277`.