False positive: Name resolution confusion between pub(crate) field and pub method in external crate
Problem Description
I am encountering a false positive error in Rust Analyzer.
I have a struct defined in an external library (dependency) that has a pub(crate) field and a pub method with the same name.
When I try to call the method from my local crate, cargo build compiles successfully, but Rust Analyzer reports an error, seemingly confusing the method call with an access to the restricted field.
Steps to Reproduce
- Create a workspace with two crates:
lib_crateandbin_crate. - In
lib_crate, define a struct with a restricted field and a public method of the same name:
// lib_crate/src/lib.rs
pub struct Worker {
pub(crate) status: i32, // The field is restricted
}
impl Worker {
pub fn new() -> Self {
Worker { status: 0 }
}
// The method has the same name
pub fn status(&self) -> i32 {
self.status
}
}
- In
bin_crate, try to call the method:
// bin_crate/src/main.rs
use lib_crate::Worker;
fn main() {
let w = Worker::new();
// ERROR: Rust Analyzer reports an error here (e.g., "field `status` is private")
// but `cargo build` passes perfectly.
let s = w.status();
}
Expected Behavior
Rust Analyzer should resolve w.status() as a method call and not report any visibility/access errors, matching rustc behavior.
Actual Behavior
Rust Analyzer highlights status with an error (e.g.,no method xxx in following function ), even though the syntax uses () indicating a method call.
Environment
- Rust Analyzer version: 0.4.2698
- Rustc version: 1.93.0-nightly
- Editor: VSCode
@rustbot label A-diagnostics
I can't reproduce, and this is also very weird, as we do distinguish between field access syntax and method call syntax.
@ChayimFriedman2 I designed a very simple package example to reproduce this problem. You can find it in yixing312/simple_case which has only one main.rs. It wrongly identified the 'base' method and treated it as a field, which led to the failure of the subsequent chained call. And on my computer, this can be achieved by using "cargo build".
The definition of the related structure is attached below.
pub struct RsBulletRobotBuilder<'a, R> {
pub(crate) _marker: PhantomData<R>,
pub(crate) rsbullet: &'a mut RsBullet,
pub(crate) load_file: &'static str,
pub(crate) base: Option<nalgebra::Isometry3<f64>>, \\This field
pub(crate) base_fixed: bool,
pub(crate) use_maximal_coordinates: Option<bool>,
pub(crate) scaling: Option<f64>,
pub(crate) flags: Option<LoadModelFlags>,
}
impl<'a, R> EntityBuilder<'a> for RsBulletRobotBuilder<'a, R> {
type Entity = RsBulletRobot<R>;
fn base(mut self, base: impl Into<nalgebra::Isometry3<f64>>) -> Self {
self.base = Some(base.into());
self
}
... \\ other method
}
Is the type of physis.builder(...) correct?
@ChayimFriedman2 I confirm it can be used with cargo build | cargo run . But when I tried to remove .base ,It still can't find the correct type.
However, it can find correct type of .robot_builder(...) ,you can see the following picture
I don't know how r-a calculates such type, but it may not be mistake of .robot_builder(...)
What is the full type of robot_builder(...)?
@ChayimFriedman2 sorry for late, I will explain how it works.
I have omitted the irrelevant code and the brief description is as follows
pub struct RsBulletRobotBuilder<'a, R> {
pub(crate) rsbullet: &'a mut RsBullet,
pub(crate) base: Option<nalgebra::Isometry3<f64>>,
...
}
impl AddRobot for RsBullet {
fn robot_builder<R: RobotFile>(&mut self, _name: impl ToString) -> RsBulletRobotBuilder<'_, R> {
RsBulletRobotBuilder {
rsbullet: self,
base: None,
...
}
}
}
The robot_builder will return an RsbulletBulider, which has a mut ref to Rsbullet. The lifecycle of RsBulletRobotBuilder and &'a mut RsBullet will end at the load() ,and then a RsBulletRobot<R> without &'a mut RsBullet begin its lifecycle.
let mut robot = physics
.robot_builder::<R>("exam_robot") \\ `RsBulletRobotBuilder<'a, R>` with `&'a mut physics` was created
.base([0., 0., 0.])
.load()? ;\\ RsBulletRobotBuilder<'a, R> was dropped, return `RsBulletRobot<R>`
This is due to the const in the definition of JakaMini2:
pub type JakaMini2 = JakaRobot<_JakaMini2, { _JakaMini2::N }>;
We cannot interpret this const, and it ends up with an error. This is causing the failure for method resolution, although I can't tell how exactly.
thank you