rust-analyzer icon indicating copy to clipboard operation
rust-analyzer copied to clipboard

False positive: Name resolution confusion between pub(crate) field and pub method in external crate

Open yixing312 opened this issue 4 weeks ago • 8 comments

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

  1. Create a workspace with two crates: lib_crate and bin_crate.
  2. 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
    }
}
  1. 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

yixing312 avatar Nov 28 '25 15:11 yixing312

@rustbot label A-diagnostics

yixing312 avatar Nov 29 '25 01:11 yixing312

I can't reproduce, and this is also very weird, as we do distinguish between field access syntax and method call syntax.

ChayimFriedman2 avatar Nov 29 '25 17:11 ChayimFriedman2

@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
}

yixing312 avatar Nov 29 '25 17:11 yixing312

Image

yixing312 avatar Nov 29 '25 18:11 yixing312

Is the type of physis.builder(...) correct?

ChayimFriedman2 avatar Nov 29 '25 19:11 ChayimFriedman2

@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.

Image

However, it can find correct type of .robot_builder(...) ,you can see the following picture

Image

I don't know how r-a calculates such type, but it may not be mistake of .robot_builder(...)

yixing312 avatar Nov 29 '25 19:11 yixing312

What is the full type of robot_builder(...)?

ChayimFriedman2 avatar Nov 29 '25 19:11 ChayimFriedman2

@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>`

yixing312 avatar Nov 30 '25 02:11 yixing312

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.

ChayimFriedman2 avatar Dec 13 '25 22:12 ChayimFriedman2

thank you

yixing312 avatar Dec 14 '25 02:12 yixing312