Skip to content

Fix issue #22100: Improve error message for non-accessible object initialization - #44642

Open
kavix wants to merge 5 commits into
ballerina-platform:masterfrom
kavix:fix-issue-22100
Open

kavix wants to merge 5 commits into
ballerina-platform:masterfrom
kavix:fix-issue-22100

Conversation

@kavix

@kavix kavix commented Jul 1, 2026 •

Copy link
Copy Markdown

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues.

The compiler complains when trying to initialize an object which has a module-level init method, which is accepted behaviour for objects across different packages. However, the error message attempt to refer to non-accessible symbol 'Obj.init' is not very user-friendly, as init is an internal compiler detail.

This PR provides a more user-friendly compile-time error message: attempt to initialize object 'Obj' with a non-accessible initialization method.

Fixes #22100

Approach

Describe how you are implementing the solutions along with the design details.

  • Added a new diagnostic error code ATTEMPT_INITIALIZE_NON_ACCESSIBLE_OBJECT in DiagnosticErrorCode.java.
  • Added the formatted error message in compiler.properties.
  • Updated checkAccessSymbol in CodeAnalyzer.java and lookupMemberSymbol in SymbolResolver.java to check if a non-accessible symbol name ends with the Names.USER_DEFINED_INIT_SUFFIX (.init).
  • If it is an init method, it strips the .init suffix to get the object name and emits the new ATTEMPT_INITIALIZE_NON_ACCESSIBLE_OBJECT error; otherwise, it falls back to the generic ATTEMPT_REFER_NON_ACCESSIBLE_SYMBOL error.

Samples

Provide high-level details about the samples related to this feature.
N/A

Remarks

List any other known issues, related PRs, TODO items, or any other notes related to the PR.
N/A

Check List

  • Read the Contributing Guide
  • Updated Change Log
  • Checked Tooling Support
  • Added necessary tests
    • Unit Tests
    • Spec Conformance Tests
    • Integration Tests
    • Ballerina By Example Tests
  • Increased Test Coverage
  • Added necessary documentation
    • API documentation
    • Module documentation in Module.md files
    • Ballerina By Examples

Improved compiler diagnostics for object initialization with a non-accessible init method. The compiler now reports a clear, user-facing error without exposing internal symbol names. Diagnostic handling was centralized, and related unit tests were updated.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c971d1cc-2881-4147-b07f-4c0d7a20f036

📥 Commits

Reviewing files that changed from the base of the PR and between 08e494f and 5a5b44a.

📒 Files selected for processing (2)
  • compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DiagnosticUtils.java
  • tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/object/ObjectWithPrivateFieldsNegativeTest.java

📝 Walkthrough

Walkthrough

This PR adds an initializer-specific diagnostic for inaccessible object initialization. Shared diagnostic handling now serves CodeAnalyzer and SymbolResolver. Object access tests expect the new messages.

Changes

Non-accessible object initializer diagnostic

Layer / File(s) Summary
Diagnostic code and message definition
compiler/ballerina-lang/.../DiagnosticErrorCode.java, compiler/ballerina-lang/.../compiler.properties
Adds ATTEMPT_INITIALIZE_NON_ACCESSIBLE_OBJECT (BCE4077) and its message template.
Centralized semantic diagnostic handling
compiler/ballerina-lang/.../DiagnosticUtils.java, compiler/ballerina-lang/.../CodeAnalyzer.java, compiler/ballerina-lang/.../SymbolResolver.java
Adds shared handling for inaccessible symbols. Both semantic analyzer call sites use it.
Initializer diagnostic validation
tests/jballerina-unit-test/.../ObjectInitializerTest.java, tests/jballerina-unit-test/.../ObjectWithPrivateFieldsNegativeTest.java
Updates expected messages for inaccessible object initialization cases.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: gimantha, maryamzi, hasithaa

Poem

A rabbit reads the message clear,
No hidden init words appear,
The compiler names the proper call,
Tests confirm the change for all,
Hop, hop—diagnostics cheer! 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the issue and the primary change: improving the error message for inaccessible object initialization.
Description check ✅ Passed The description follows the repository template and documents the purpose, approach, samples, remarks, checklist, and linked issue.
Linked Issues check ✅ Passed The changes satisfy issue #22100 by reporting a user-friendly initialization error while preserving rejection of inaccessible initializers.
Out of Scope Changes check ✅ Passed All changes are directly related to the diagnostic improvement, implementation, compiler message, and supporting tests for issue #22100.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java (1)

3646-3660: 📐 Maintainability & Code Quality | 🔵 Trivial

Duplicate logic with SymbolResolver.lookupMemberSymbol.

The exact same suffix-check/substring logic to detect a non-accessible init method and derive the object name is duplicated here and in SymbolResolver.lookupMemberSymbol (lines 981-987). Consider extracting a shared helper (e.g., a static method returning the diagnostic code + object name, or placed in Names/a diagnostics utility) to avoid the two implementations drifting apart.

♻️ Suggested consolidation
-    private void checkAccessSymbol(BSymbol symbol, PackageID pkgID, Location position) {
-        if (symbol == null) {
-            return;
-        }
-
-        if (!pkgID.equals(symbol.pkgID) && !Symbols.isPublic(symbol)) {
-            if (symbol.name.value.endsWith("." + Names.USER_DEFINED_INIT_SUFFIX.value)) {
-                String objName = symbol.name.value.substring(0,
-                        symbol.name.value.length() - Names.USER_DEFINED_INIT_SUFFIX.value.length() - 1);
-                dlog.error(position, DiagnosticErrorCode.ATTEMPT_INITIALIZE_NON_ACCESSIBLE_OBJECT, objName);
-            } else {
-                dlog.error(position, DiagnosticErrorCode.ATTEMPT_REFER_NON_ACCESSIBLE_SYMBOL, symbol.name);
-            }
-        }
-    }
+    private void checkAccessSymbol(BSymbol symbol, PackageID pkgID, Location position) {
+        if (symbol == null) {
+            return;
+        }
+
+        if (!pkgID.equals(symbol.pkgID) && !Symbols.isPublic(symbol)) {
+            DiagnosticUtils.reportNonAccessibleSymbol(dlog, position, symbol);
+        }
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java`
around lines 3646 - 3660, The init-method accessibility check in
CodeAnalyzer.checkAccessSymbol duplicates the same suffix parsing logic already
used in SymbolResolver.lookupMemberSymbol, so extract that non-accessible-init
detection and object-name derivation into a shared helper. Reuse the helper from
both checkAccessSymbol and lookupMemberSymbol, keeping the diagnostic selection
and extracted object name in one place so the behavior stays consistent and does
not drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java`:
- Around line 3646-3660: The init-method accessibility check in
CodeAnalyzer.checkAccessSymbol duplicates the same suffix parsing logic already
used in SymbolResolver.lookupMemberSymbol, so extract that non-accessible-init
detection and object-name derivation into a shared helper. Reuse the helper from
both checkAccessSymbol and lookupMemberSymbol, keeping the diagnostic selection
and extracted object name in one place so the behavior stays consistent and does
not drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bd433f30-5e1b-4f13-8149-060e46efdb0a

📥 Commits

Reviewing files that changed from the base of the PR and between f785da2 and 3a3d1d5.

📒 Files selected for processing (5)
  • compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java
  • compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java
  • compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SymbolResolver.java
  • compiler/ballerina-lang/src/main/resources/compiler.properties
  • tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/object/ObjectInitializerTest.java

@kavix

kavix commented Jul 28, 2026

Copy link
Copy Markdown
Author

Hi @MaryamZi @gimantha @hasithaa @sameerajayasoma — this PR has been open for a bit and is ready for review. It's a small compiler fix for #22100 (improving the error message when initializing an object with a non-accessible init). All checks are green. Could someone take a look when you have a chance? Thanks!

Comment on lines +3652 to +3658
if (symbol.name.value.endsWith("." + Names.USER_DEFINED_INIT_SUFFIX.value)) {
String objName = symbol.name.value.substring(0,
symbol.name.value.length() - Names.USER_DEFINED_INIT_SUFFIX.value.length() - 1);
dlog.error(position, DiagnosticErrorCode.ATTEMPT_INITIALIZE_NON_ACCESSIBLE_OBJECT, objName);
} else {
dlog.error(position, DiagnosticErrorCode.ATTEMPT_REFER_NON_ACCESSIBLE_SYMBOL, symbol.name);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have added the same code in both places. Can you check if you ca reuse the code block?
Also why are we logging the same error from two different phases (CodeAnalyzer and SymbolResolver)?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have added the same code in both places. Can you check if you ca reuse the code block? Also why are we logging the same error from two different phases (CodeAnalyzer and SymbolResolver)?

Hi @gimantha,

Thanks for pointing this out! I investigated both call sites to trace how symbol access is checked during compilation:

Why SymbolResolver was redundant

  • When compiling an object initialization expression like new pkg:Student(), TypeChecker resolves the public type Student and directly attaches the initializer function symbol (((BObjectTypeSymbol)actualType.tsymbol).initializerFunc.symbol) to initInvocation.symbol.
  • It bypasses SymbolResolver.lookupMemberSymbol for the init method lookup.
    Later, during the CodeAnalyzer phase, checkAccess() visits the BLangInvocation node for initInvocation and delegates to checkAccessSymbol(). This is where the accessibility of non-public init methods across - package boundaries is actually evaluated and logged.

Resolution

  • Since SymbolResolver.lookupMemberSymbol is never reached for init access during new expressions, I have removed the redundant logic from SymbolResolver.java and kept the check exclusively in CodeAnalyzer.java.

Existing unit tests pass cleanly with this change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets extract out the common logic to a different method and reuse it in both places

@kavix kavix Aug 3, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets extract out the common logic to a different method and reuse it in both places

@gimantha Thanks! I have extracted the shared diagnostic logic into a helper method DiagnosticUtils.logNonAccessibleSymbolError() within org.wso2.ballerinalang. compiler.semantics.analyzer and updated both CodeAnalyzer.java (checkAccessSymbol) and SymbolResolver.java (lookupMemberSymbol) to call it.

@kavix
kavix requested a review from gimantha August 1, 2026 09:39
kavix added 2 commits August 3, 2026 10:58
Extracted non-accessible symbol error logging into a new `DiagnosticUtils` helper and replaced duplicated logic in `CodeAnalyzer` and `SymbolResolver`. This centralizes diagnostic behavior and ensures inaccessible object initializer references consistently report `ATTEMPT_INITIALIZE_NON_ACCESSIBLE_OBJECT` instead of the generic symbol access error.

Signed-off-by: kavix <kavix@yahoo.com>
…iagnostic

Signed-off-by: kavix <kavix@yahoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User friendly compile time error message when using new with a class that has an init method with module-level visibility

2 participants