Skip to content

Commit 9680405

Browse files
Rollup merge of rust-lang#153556 - CoCo-Japan-pan:impl-restriction-lowering, r=petrochenkov
`impl` restriction lowering This PR is linked to a [GSoC proposal](https://github.com/rust-lang/google-summer-of-code?tab=readme-ov-file#implementing-impl-and-mut-restrictions) and is part of the progress toward implementing `impl` restrictions proposed in [RFC 3323](https://rust-lang.github.io/rfcs/3323-restrictions.html). This PR implements path resolution for `impl` restrictions. The resolution is performed in `rustc_resolve/src/late.rs` using `smart_resolve_path`. This PR also checks whether the restricted module or crate is an ancestor. If it is not, it emits a restriction-specific counterpart to visibility’s `AncestorOnly` error. r? @Urgau cc @jhpratt
2 parents a8d5047 + 4a60dae commit 9680405

4 files changed

Lines changed: 268 additions & 4 deletions

File tree

compiler/rustc_resolve/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ pub(crate) struct ExpectedModuleFound {
560560
#[diag("cannot determine resolution for the visibility", code = E0578)]
561561
pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span);
562562

563+
#[derive(Diagnostic)]
564+
#[diag("trait implementation can only be restricted to ancestor modules")]
565+
pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span);
566+
563567
#[derive(Diagnostic)]
564568
#[diag("cannot use a tool module through an import")]
565569
pub(crate) struct ToolModuleImported {

compiler/rustc_resolve/src/late.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
452452
DefineOpaques,
453453
/// Resolving a macro
454454
Macro,
455+
/// Paths for module or crate root. Used for restrictions.
456+
Module,
455457
}
456458

457459
impl PathSource<'_, '_, '_> {
@@ -460,7 +462,8 @@ impl PathSource<'_, '_, '_> {
460462
PathSource::Type
461463
| PathSource::Trait(_)
462464
| PathSource::Struct(_)
463-
| PathSource::DefineOpaques => TypeNS,
465+
| PathSource::DefineOpaques
466+
| PathSource::Module => TypeNS,
464467
PathSource::Expr(..)
465468
| PathSource::Pat
466469
| PathSource::TupleStruct(..)
@@ -485,7 +488,8 @@ impl PathSource<'_, '_, '_> {
485488
| PathSource::DefineOpaques
486489
| PathSource::Delegation
487490
| PathSource::PreciseCapturingArg(..)
488-
| PathSource::Macro => false,
491+
| PathSource::Macro
492+
| PathSource::Module => false,
489493
}
490494
}
491495

@@ -528,6 +532,7 @@ impl PathSource<'_, '_, '_> {
528532
PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
529533
PathSource::PreciseCapturingArg(..) => "type or const parameter",
530534
PathSource::Macro => "macro",
535+
PathSource::Module => "module",
531536
}
532537
}
533538

@@ -626,6 +631,7 @@ impl PathSource<'_, '_, '_> {
626631
),
627632
PathSource::PreciseCapturingArg(MacroNS) => false,
628633
PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)),
634+
PathSource::Module => matches!(res, Res::Def(DefKind::Mod, _)),
629635
}
630636
}
631637

@@ -646,6 +652,12 @@ impl PathSource<'_, '_, '_> {
646652
(PathSource::PreciseCapturingArg(..), true) => E0799,
647653
(PathSource::PreciseCapturingArg(..), false) => E0800,
648654
(PathSource::Macro, _) => E0425,
655+
// FIXME: There is no dedicated error code for this case yet.
656+
// E0577 already covers the same situation for visibilities,
657+
// so we reuse it here for now. It may make sense to generalize
658+
// it for restrictions in the future.
659+
(PathSource::Module, true) => E0577,
660+
(PathSource::Module, false) => E0433,
649661
}
650662
}
651663
}
@@ -2174,7 +2186,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
21742186
| PathSource::Type
21752187
| PathSource::PreciseCapturingArg(..)
21762188
| PathSource::ReturnTypeNotation
2177-
| PathSource::Macro => false,
2189+
| PathSource::Macro
2190+
| PathSource::Module => false,
21782191
PathSource::Expr(..)
21792192
| PathSource::Pat
21802193
| PathSource::Struct(_)
@@ -2800,7 +2813,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
28002813
self.diag_metadata.current_impl_items = None;
28012814
}
28022815

2803-
ItemKind::Trait(box Trait { generics, bounds, items, .. }) => {
2816+
ItemKind::Trait(box Trait { generics, bounds, items, impl_restriction, .. }) => {
2817+
// resolve paths for `impl` restrictions
2818+
self.resolve_impl_restriction_path(impl_restriction);
2819+
28042820
// Create a new rib for the trait-wide type parameters.
28052821
self.with_generic_param_rib(
28062822
&generics.params,
@@ -4389,6 +4405,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
43894405
}
43904406
}
43914407

4408+
fn resolve_impl_restriction_path(&mut self, restriction: &'ast ast::ImplRestriction) {
4409+
match &restriction.kind {
4410+
ast::RestrictionKind::Unrestricted => (),
4411+
ast::RestrictionKind::Restricted { path, id, shorthand: _ } => {
4412+
self.smart_resolve_path(*id, &None, path, PathSource::Module);
4413+
if let Some(res) = self.r.partial_res_map[&id].full_res()
4414+
&& let Some(def_id) = res.opt_def_id()
4415+
{
4416+
if !self.r.is_accessible_from(
4417+
Visibility::Restricted(def_id),
4418+
self.parent_scope.module,
4419+
) {
4420+
self.r.dcx().create_err(errors::RestrictionAncestorOnly(path.span)).emit();
4421+
}
4422+
}
4423+
}
4424+
}
4425+
}
4426+
43924427
// High-level and context dependent path resolution routine.
43934428
// Resolves the path and records the resolution into definition map.
43944429
// If resolution fails tries several techniques to find likely
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#![feature(impl_restriction)]
2+
#![expect(incomplete_features)]
3+
4+
pub mod a {
5+
pub enum E {}
6+
pub mod d {}
7+
pub mod b {
8+
pub mod c {}
9+
10+
// We do not use crate-relative paths here, since we follow the
11+
// "uniform paths" approach used for type/expression paths.
12+
pub impl(in a::b) trait T1 {} //~ ERROR cannot find module or crate `a` in this scope [E0433]
13+
14+
pub impl(in ::std) trait T2 {} //~ ERROR trait implementation can only be restricted to ancestor modules
15+
16+
pub impl(in self::c) trait T3 {} //~ ERROR trait implementation can only be restricted to ancestor modules
17+
18+
pub impl(in super::d) trait T4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
19+
20+
pub impl(in crate::c) trait T5 {} //~ ERROR cannot find module `c` in the crate root [E0433]
21+
22+
pub impl(in super::E) trait T6 {} //~ ERROR expected module, found enum `super::E` [E0577]
23+
24+
pub impl(in super::super::super) trait T7 {} //~ ERROR too many leading `super` keywords [E0433]
25+
26+
// OK paths
27+
pub impl(crate) trait T8 {}
28+
pub impl(self) trait T9 {}
29+
pub impl(super) trait T10 {}
30+
pub impl(in crate::a) trait T11 {}
31+
pub impl(in super::super) trait T12 {}
32+
33+
// Check if we can resolve paths referring to modules declared later.
34+
pub impl(in self::f) trait L1 {} //~ ERROR trait implementation can only be restricted to ancestor modules
35+
36+
pub impl(in super::G) trait L2 {} //~ ERROR expected module, found enum `super::G` [E0577]
37+
38+
pub impl(in super::h) trait L3 {} //~ ERROR trait implementation can only be restricted to ancestor modules
39+
40+
pub mod f {}
41+
}
42+
43+
pub enum G {}
44+
pub mod h {}
45+
}
46+
47+
pub impl(in crate::a) trait T13 {} //~ ERROR trait implementation can only be restricted to ancestor modules
48+
49+
pub impl(in crate::a::E) trait T14 {} //~ ERROR expected module, found enum `crate::a::E` [E0577]
50+
51+
pub impl(crate) trait T15 {}
52+
pub impl(self) trait T16 {}
53+
54+
pub impl(super) trait T17 {} //~ ERROR too many leading `super` keywords [E0433]
55+
56+
// Check if we can resolve paths referring to modules declared later.
57+
pub impl(in crate::j) trait L4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
58+
59+
pub impl(in crate::I) trait L5 {} //~ ERROR expected module, found enum `crate::I` [E0577]
60+
61+
pub enum I {}
62+
pub mod j {}
63+
64+
// Check if we can resolve `use`d paths.
65+
mod m1 {
66+
pub impl(in crate::m2) trait U1 {} // OK
67+
}
68+
69+
use m1 as m2;
70+
71+
mod m3 {
72+
mod m4 {
73+
pub impl(in crate::m2) trait U2 {} //~ ERROR trait implementation can only be restricted to ancestor modules
74+
pub impl(in m6) trait U3 {} // OK
75+
pub impl(in m6::m5) trait U4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
76+
pub impl(in m7) trait U5 {} //~ ERROR expected module, found enum `m7` [E0577]
77+
78+
use crate::m3 as m6;
79+
use crate::m3::E as m7;
80+
}
81+
mod m5 {}
82+
pub enum E {}
83+
}
84+
85+
fn main() {}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
error: trait implementation can only be restricted to ancestor modules
2+
--> $DIR/restriction_resolution_errors.rs:14:21
3+
|
4+
LL | pub impl(in ::std) trait T2 {}
5+
| ^^^^^
6+
7+
error: trait implementation can only be restricted to ancestor modules
8+
--> $DIR/restriction_resolution_errors.rs:16:21
9+
|
10+
LL | pub impl(in self::c) trait T3 {}
11+
| ^^^^^^^
12+
13+
error: trait implementation can only be restricted to ancestor modules
14+
--> $DIR/restriction_resolution_errors.rs:18:21
15+
|
16+
LL | pub impl(in super::d) trait T4 {}
17+
| ^^^^^^^^
18+
19+
error[E0433]: too many leading `super` keywords
20+
--> $DIR/restriction_resolution_errors.rs:24:35
21+
|
22+
LL | pub impl(in super::super::super) trait T7 {}
23+
| ^^^^^ there are too many leading `super` keywords
24+
25+
error: trait implementation can only be restricted to ancestor modules
26+
--> $DIR/restriction_resolution_errors.rs:34:21
27+
|
28+
LL | pub impl(in self::f) trait L1 {}
29+
| ^^^^^^^
30+
31+
error: trait implementation can only be restricted to ancestor modules
32+
--> $DIR/restriction_resolution_errors.rs:38:21
33+
|
34+
LL | pub impl(in super::h) trait L3 {}
35+
| ^^^^^^^^
36+
37+
error: trait implementation can only be restricted to ancestor modules
38+
--> $DIR/restriction_resolution_errors.rs:47:13
39+
|
40+
LL | pub impl(in crate::a) trait T13 {}
41+
| ^^^^^^^^
42+
43+
error[E0433]: too many leading `super` keywords
44+
--> $DIR/restriction_resolution_errors.rs:54:10
45+
|
46+
LL | pub impl(super) trait T17 {}
47+
| ^^^^^ there are too many leading `super` keywords
48+
49+
error: trait implementation can only be restricted to ancestor modules
50+
--> $DIR/restriction_resolution_errors.rs:57:13
51+
|
52+
LL | pub impl(in crate::j) trait L4 {}
53+
| ^^^^^^^^
54+
55+
error: trait implementation can only be restricted to ancestor modules
56+
--> $DIR/restriction_resolution_errors.rs:73:21
57+
|
58+
LL | pub impl(in crate::m2) trait U2 {}
59+
| ^^^^^^^^^
60+
61+
error: trait implementation can only be restricted to ancestor modules
62+
--> $DIR/restriction_resolution_errors.rs:75:21
63+
|
64+
LL | pub impl(in m6::m5) trait U4 {}
65+
| ^^^^^^
66+
67+
error[E0433]: cannot find module or crate `a` in this scope
68+
--> $DIR/restriction_resolution_errors.rs:12:21
69+
|
70+
LL | pub impl(in a::b) trait T1 {}
71+
| ^ use of unresolved module or unlinked crate `a`
72+
|
73+
help: there is a crate or module with a similar name
74+
|
75+
LL - pub impl(in a::b) trait T1 {}
76+
LL + pub impl(in c::b) trait T1 {}
77+
|
78+
help: consider importing this module
79+
|
80+
LL + use a;
81+
|
82+
83+
error[E0433]: cannot find module `c` in the crate root
84+
--> $DIR/restriction_resolution_errors.rs:20:28
85+
|
86+
LL | pub impl(in crate::c) trait T5 {}
87+
| ^ not found in the crate root
88+
89+
error[E0577]: expected module, found enum `super::E`
90+
--> $DIR/restriction_resolution_errors.rs:22:21
91+
|
92+
LL | pub impl(in super::E) trait T6 {}
93+
| ^^^^^^^^ not a module
94+
95+
error[E0577]: expected module, found enum `super::G`
96+
--> $DIR/restriction_resolution_errors.rs:36:21
97+
|
98+
LL | pub impl(in super::G) trait L2 {}
99+
| ^^^^^^^^ not a module
100+
101+
error[E0577]: expected module, found enum `crate::a::E`
102+
--> $DIR/restriction_resolution_errors.rs:49:13
103+
|
104+
LL | pub mod b {
105+
| --------- similarly named module `b` defined here
106+
...
107+
LL | pub impl(in crate::a::E) trait T14 {}
108+
| ^^^^^^^^^^^
109+
|
110+
help: a module with a similar name exists
111+
|
112+
LL - pub impl(in crate::a::E) trait T14 {}
113+
LL + pub impl(in crate::a::b) trait T14 {}
114+
|
115+
116+
error[E0577]: expected module, found enum `crate::I`
117+
--> $DIR/restriction_resolution_errors.rs:59:13
118+
|
119+
LL | pub mod a {
120+
| --------- similarly named module `a` defined here
121+
...
122+
LL | pub impl(in crate::I) trait L5 {}
123+
| ^^^^^^^^
124+
|
125+
help: a module with a similar name exists
126+
|
127+
LL - pub impl(in crate::I) trait L5 {}
128+
LL + pub impl(in crate::a) trait L5 {}
129+
|
130+
131+
error[E0577]: expected module, found enum `m7`
132+
--> $DIR/restriction_resolution_errors.rs:76:21
133+
|
134+
LL | pub impl(in m7) trait U5 {}
135+
| ^^ not a module
136+
137+
error: aborting due to 18 previous errors
138+
139+
Some errors have detailed explanations: E0433, E0577.
140+
For more information about an error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)