Skip to content

Semantic checks of impl restrictions#154661

Open
CoCo-Japan-pan wants to merge 9 commits intorust-lang:mainfrom
CoCo-Japan-pan:impl-restriction-check
Open

Semantic checks of impl restrictions#154661
CoCo-Japan-pan wants to merge 9 commits intorust-lang:mainfrom
CoCo-Japan-pan:impl-restriction-check

Conversation

@CoCo-Japan-pan
Copy link
Copy Markdown
Contributor

@CoCo-Japan-pan CoCo-Japan-pan commented Apr 1, 2026

View all comments

This PR implements semantic checks for impl restrictions proposed in the Restrictions RFC (Tracking Issue #105077), and linked to a GSOC idea/proposal.

It lowers the resolved paths of impl restrictions from the AST to HIR and into TraitDef, and integrates the checks into the coherence phase by extending check_impl. As parsing (#152943) and path resolution (#153556) have already been implemented, this PR provides a working implementation of impl restrictions.

r? @Urgau
cc @jhpratt

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 1, 2026

Some changes occurred in compiler/rustc_passes/src/check_attr.rs

cc @jdonszelmann, @JonathanBrouwer

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Apr 1, 2026
@CoCo-Japan-pan CoCo-Japan-pan changed the title Impl restriction check impl restriction check Apr 1, 2026
@CoCo-Japan-pan CoCo-Japan-pan changed the title impl restriction check Semantic checks of impl restrictions Apr 1, 2026
Copy link
Copy Markdown
Member

@Urgau Urgau left a comment

Choose a reason for hiding this comment

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

Looks promising. Left some preliminary comments.

View changes since this review

Comment on lines +139 to +143
if restricted_to.krate == krate {
tcx.def_path_str(restricted_to)
} else {
tcx.crate_name(restricted_to.krate).to_ident_string()
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't seems right. tcx.crate_name will only return the default crate name, but one can rename a crate when importing it, eg with extern crate serde as another_serde; or in Cargo.toml.

I think it would be safer to only call def_path_str here.

Comment on lines +9 to +10
impl external::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction`
impl external::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's what I was talking about, the error here refers to external_impl_restriction instead of external.

Suggested change
impl external::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction`
impl external::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external_impl_restriction`
impl external::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external`
impl external::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external`

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.

When we use def_path_str for external crates, the second one will be inner instead of external::inner.
Maybe we should use with_no_trimmed_paths!?

Copy link
Copy Markdown
Member

@Urgau Urgau Apr 4, 2026

Choose a reason for hiding this comment

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

You can try with with_no_trimmed_paths!, though I'm surprised it gives you inner and not external::inner. I wonder if def_path_str is a bit confused with external definitions.

Looking at the different overrides maybe with_resolve_crate_name! would be better for us here, as it would avoid always printing the crate name when not necessary.

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.

with_resolve_crate_name!(tcx.def_path_str(restricted_to)) seems to output the same result as tcx.def_path_str(restricted_to) in these test cases, which gives us inner instead of external::inner.

// For local definitions, we need to prepend with crate name.
with_resolve_crate_name!(with_no_trimmed_paths!(self.tcx.def_path_str(def_id)))

Only using with_no_trimmed_paths! yields external::inner, while local items appear to omit the crate prefix (e.g., foo::bar).
On the other hand, with_resolve_crate_name!(with_no_trimmed_paths!(self.tcx.def_path_str(def_id))) does not omit the prefix for local items, but uses the crate name (e.g., impl_restriction_check::foo::bar) instead of crate.

Would it make sense to use with_no_trimmed_paths! and then explicitly add the crate prefix for local items?
Or maybe we should just use with_no_trimmed_paths! or with_resolve_crate_name!(with_no_trimmed_paths!(..))?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Given your description it seems like we could with_crate_name! + with_no_trimmed_paths! to get crate:: prefix for local modules and full path for external modules.

It that doesn't work, let's just use with_no_trimmed_paths!. The most important being that we get the resolved crate name when pointing at external modules.

pub(crate) impl(super) trait Bar {}
pub impl(crate) trait Baz {}
pub(crate) impl(in crate::foo::bar) trait Qux {}
pub(crate) impl(in crate::foo) trait FooBar {}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add test case where it's impl(in crate::bar) here, so we can make sure it's not implementable here.

Same with a impl(in external).

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.

crate::bar would be an invalid path, and external is not an ancestor, so both cases should already result in errors during path resolution. Is that what you had in mind?

Copy link
Copy Markdown
Member

@Urgau Urgau Apr 3, 2026

Choose a reason for hiding this comment

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

Well mod bar {} would need to be created, but yes, I would like to have a test for those two cases.

In general, it's always good add tests for edge-case, even if they appear "impossible", you never know what users will throw at the compiler.

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.

For ancestor-related errors involving restrictions to other crates, it might make sense to add such cases to restriction_resolution_errors.rs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I was pointing here since there is already an aux-build, but feel free to put it where you think it makes the most sense.

@Urgau Urgau added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants