Skip to content

fix(semantic): Address remaining cases of undeclared identifier diagnostics - #2300

Open
ggiraldez wants to merge 11 commits into
ggiraldez/undeclared-type-namesfrom
ggiraldez/sdr-resolution-gaps
Open

ggiraldez wants to merge 11 commits into
ggiraldez/undeclared-type-namesfrom
ggiraldez/sdr-resolution-gaps

Conversation

@ggiraldez

@ggiraldez ggiraldez commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Closes most of the gaps left for NomicFoundation/slang-diagnostics-research#1473, NomicFoundation/slang-diagnostics-research#1686, NomicFoundation/slang-diagnostics-research#1750 and NomicFoundation/slang-diagnostics-research#1751, found by running each issue's listed solc tests through slang. The issues can be closed after merging both this PR and #2326.

Closes #2338

A library's external functions are no longer visible by bare name inside the library. super skips unimplemented functions, so it reaches the next implemented base or reports the member as missing. Through the name of a contract or interface the code doesn't derive from, only its types, errors and externally visible functions are reachable (and events from 0.8.21). This applies to member access, emit paths and storage layout expressions, and emit/revert targets are now resolved in p5 to keep that logic in one pass. A function attached with using only as an operator is no longer callable as a member. Binding a receiver to an attached function now checks data locations: by the internal or ABI rules depending on the function's visibility, and a storage parameter always needs a storage receiver.

There's a remaining case for .selector on a ternary of library functions, eg. (cond ? L.f : L.f).selector, which needs a separate function-type redesign.

@ggiraldez
ggiraldez added this pull request to stack #2287 October 20, 2026 00:02
@changeset-bot

changeset-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 476b5cf

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ggiraldez
ggiraldez marked this pull request as ready for review October 20, 2026 00:06
@ggiraldez
ggiraldez requested review from a team as code owners October 20, 2026 00:06
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchggiraldez/sdr-resolution-gaps
Testbedci

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

🚨 3 Alerts

🐰 View full continuous benchmarking report in Bencher

@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch 2 times, most recently from 8cef9da to 6174cb8 Compare October 27, 2026 23:56
@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch from 6174cb8 to 40c10d5 Compare October 28, 2026 00:57
@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch from 40c10d5 to c4a390b Compare October 28, 2026 22:46
@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch from c4a390b to 3827d9c Compare October 29, 2026 17:14
@ggiraldez
ggiraldez marked this pull request as draft October 29, 2026 22:23
@ggiraldez

Copy link
Copy Markdown
Contributor Author

Flipping back to draft. I found additional cases of the mentioned SDR issues that make sense to fix here.

@teofr teofr left a comment

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.

Did a first pass, will continue later

│ ╰───── ref: 2
│ │
│ ╰── ref: 4
12 │ a + a;

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.

Should we add a ref: entry to the +? And other operators?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Operators don't generate References so they cannot appear in binder snapshots.

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.

Makes sense, not for this PR, but I wonder if we should? In situations like this one the operator works almost like any othr function call, and refers to the add method, rather than a builtin.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can't do that without a sizeable refactor. References can currently only point to Identifiers. What we can do is use the AST's resolve_operator_to_function and only report the resolved operator in the binder report. That will still require some work, but it's doable.

ir::StateVariableVisibility::Public
)
}
_ => true,

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.

I was randomly asking questions to claude about the pr, and it brought up that this may be wrong (I know, not part of this PR, but I think is relevant to these diagnostics). It suggests changing this to _ => false, this doesn't play nicely with other parts of our codebase, but may be worth a check (even in another PR).

This test fails in solc with error 9582 but it's accepted on slang

// SPDX-License-Identifier: MIT
pragma solidity *;

contract C {
    struct S {
        uint256 a;
    }

    function g() public view {
        this.S;
    }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's probably true for p5 (ie. in an expression resolution context), but this function is also used for general qualified scope lookup (eg. for types/events/errors/etc) and in that case, it's not cut and dried. In fact, your previous question about event visibility from 0.8.21 onwards is one such case. I'll add it to my TODO list for later.

@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch from e235a85 to c8d44d2 Compare November 2, 2026 21:10
@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch from c8d44d2 to 375332b Compare November 2, 2026 23:10

@teofr teofr left a comment

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.

Looks good, just some questions and nits, but up to you

/// Whether a member of a contract or interface can be reached through its
/// name from outside the contract's hierarchy: types, errors and
/// externally visible functions can, events only from 0.8.21, and
/// variables and internal functions never.

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.

Suggested change
/// variables and internal functions never.
/// variables, modifiers, and internal functions never.

Comment on lines +385 to +389
} else if let Some(member) = self.unreachable_qualified_member(identifier_path) {
self.binder
.fixup_reference(member.id(), Resolution::Unresolved);
let kind = namespace_member_not_found(identifier_path, identifier_path.len() - 1);
self.push_diagnostic(member, kind);

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.

I'm not the biggest fan of this fixup, I wonder if we could make resolve_identifier_path_as_expression_in_scope do all the work. However, I don't have a stron idea on how to approach it, so I'd leave it for now. If you have any ideas or a strong reason why this should behave this way I'm interested in hearing it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed it's not ideal. I've been thinking that we've outgrown the resolution capabilities of the binder and we're spilling binding policy all over the passes. I would defer it to another PR though.

@ggiraldez
ggiraldez force-pushed the ggiraldez/sdr-resolution-gaps branch from 375332b to 476b5cf Compare November 3, 2026 22:38

This branch has not been deployed

No deployments
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.

string has a length member

2 participants