Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,10 @@ pub(crate) struct ExpectedModuleFound {
#[diag("cannot determine resolution for the visibility", code = E0578)]
pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span);

#[derive(Diagnostic)]
#[diag("trait implementation can only be restricted to ancestor modules")]
pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span);

#[derive(Diagnostic)]
#[diag("cannot use a tool module through an import")]
pub(crate) struct ToolModuleImported {
Expand Down
43 changes: 39 additions & 4 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
DefineOpaques,
/// Resolving a macro
Macro,
/// Paths for module or crate root. Used for restrictions.
Module,
}

impl PathSource<'_, '_, '_> {
Expand All @@ -461,7 +463,8 @@ impl PathSource<'_, '_, '_> {
PathSource::Type
| PathSource::Trait(_)
| PathSource::Struct(_)
| PathSource::DefineOpaques => TypeNS,
| PathSource::DefineOpaques
| PathSource::Module => TypeNS,
PathSource::Expr(..)
| PathSource::Pat
| PathSource::TupleStruct(..)
Expand All @@ -486,7 +489,8 @@ impl PathSource<'_, '_, '_> {
| PathSource::DefineOpaques
| PathSource::Delegation
| PathSource::PreciseCapturingArg(..)
| PathSource::Macro => false,
| PathSource::Macro
| PathSource::Module => false,
}
}

Expand Down Expand Up @@ -529,6 +533,7 @@ impl PathSource<'_, '_, '_> {
PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
PathSource::PreciseCapturingArg(..) => "type or const parameter",
PathSource::Macro => "macro",
PathSource::Module => "module",
}
}

Expand Down Expand Up @@ -627,6 +632,7 @@ impl PathSource<'_, '_, '_> {
),
PathSource::PreciseCapturingArg(MacroNS) => false,
PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)),
PathSource::Module => matches!(res, Res::Def(DefKind::Mod, _)),
}
}

Expand All @@ -647,6 +653,12 @@ impl PathSource<'_, '_, '_> {
(PathSource::PreciseCapturingArg(..), true) => E0799,
(PathSource::PreciseCapturingArg(..), false) => E0800,
(PathSource::Macro, _) => E0425,
// FIXME: There is no dedicated error code for this case yet.
// E0577 already covers the same situation for visibilities,
// so we reuse it here for now. It may make sense to generalize
// it for restrictions in the future.
(PathSource::Module, true) => E0577,
(PathSource::Module, false) => E0433,
}
}
}
Expand Down Expand Up @@ -2175,7 +2187,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
| PathSource::Type
| PathSource::PreciseCapturingArg(..)
| PathSource::ReturnTypeNotation
| PathSource::Macro => false,
| PathSource::Macro
| PathSource::Module => false,
PathSource::Expr(..)
| PathSource::Pat
| PathSource::Struct(_)
Expand Down Expand Up @@ -2801,7 +2814,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.diag_metadata.current_impl_items = None;
}

ItemKind::Trait(box Trait { generics, bounds, items, .. }) => {
ItemKind::Trait(box Trait { generics, bounds, items, impl_restriction, .. }) => {
// resolve paths for `impl` restrictions
self.resolve_impl_restriction_path(impl_restriction);

// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(
&generics.params,
Expand Down Expand Up @@ -4390,6 +4406,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
}

fn resolve_impl_restriction_path(&mut self, restriction: &'ast ast::ImplRestriction) {
match &restriction.kind {
ast::RestrictionKind::Unrestricted => (),
ast::RestrictionKind::Restricted { path, id, shorthand: _ } => {
self.smart_resolve_path(*id, &None, path, PathSource::Module);
if let Some(res) = self.r.partial_res_map[&id].full_res()
&& let Some(def_id) = res.opt_def_id()
{
if !self.r.is_accessible_from(
Visibility::Restricted(def_id),
self.parent_scope.module,
) {
self.r.dcx().create_err(errors::RestrictionAncestorOnly(path.span)).emit();
}
}
}
}
}

// High-level and context dependent path resolution routine.
// Resolves the path and records the resolution into definition map.
// If resolution fails tries several techniques to find likely
Expand Down
85 changes: 85 additions & 0 deletions tests/ui/impl-restriction/restriction_resolution_errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#![feature(impl_restriction)]
#![expect(incomplete_features)]

pub mod a {
pub enum E {}
pub mod d {}
pub mod b {
pub mod c {}

// We do not use crate-relative paths here, since we follow the
// "uniform paths" approach used for type/expression paths.
pub impl(in a::b) trait T1 {} //~ ERROR cannot find module or crate `a` in this scope [E0433]

pub impl(in ::std) trait T2 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub impl(in self::c) trait T3 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub impl(in super::d) trait T4 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub impl(in crate::c) trait T5 {} //~ ERROR cannot find module `c` in the crate root [E0433]

pub impl(in super::E) trait T6 {} //~ ERROR expected module, found enum `super::E` [E0577]

pub impl(in super::super::super) trait T7 {} //~ ERROR too many leading `super` keywords [E0433]

// OK paths
pub impl(crate) trait T8 {}
pub impl(self) trait T9 {}
pub impl(super) trait T10 {}
pub impl(in crate::a) trait T11 {}
pub impl(in super::super) trait T12 {}

// Check if we can resolve paths referring to modules declared later.
pub impl(in self::f) trait L1 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub impl(in super::G) trait L2 {} //~ ERROR expected module, found enum `super::G` [E0577]

pub impl(in super::h) trait L3 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub mod f {}
}

pub enum G {}
pub mod h {}
}

pub impl(in crate::a) trait T13 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub impl(in crate::a::E) trait T14 {} //~ ERROR expected module, found enum `crate::a::E` [E0577]

pub impl(crate) trait T15 {}
pub impl(self) trait T16 {}

pub impl(super) trait T17 {} //~ ERROR too many leading `super` keywords [E0433]

// Check if we can resolve paths referring to modules declared later.
pub impl(in crate::j) trait L4 {} //~ ERROR trait implementation can only be restricted to ancestor modules

pub impl(in crate::I) trait L5 {} //~ ERROR expected module, found enum `crate::I` [E0577]

pub enum I {}
pub mod j {}

// Check if we can resolve `use`d paths.
mod m1 {
pub impl(in crate::m2) trait U1 {} // OK
}

use m1 as m2;

mod m3 {
mod m4 {
pub impl(in crate::m2) trait U2 {} //~ ERROR trait implementation can only be restricted to ancestor modules
pub impl(in m6) trait U3 {} // OK
pub impl(in m6::m5) trait U4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
pub impl(in m7) trait U5 {} //~ ERROR expected module, found enum `m7` [E0577]

use crate::m3 as m6;
use crate::m3::E as m7;
}
mod m5 {}
pub enum E {}
}

fn main() {}
140 changes: 140 additions & 0 deletions tests/ui/impl-restriction/restriction_resolution_errors.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:14:21
|
LL | pub impl(in ::std) trait T2 {}
| ^^^^^

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:16:21
|
LL | pub impl(in self::c) trait T3 {}
| ^^^^^^^

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:18:21
|
LL | pub impl(in super::d) trait T4 {}
| ^^^^^^^^

error[E0433]: too many leading `super` keywords
--> $DIR/restriction_resolution_errors.rs:24:35
|
LL | pub impl(in super::super::super) trait T7 {}
| ^^^^^ there are too many leading `super` keywords

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:34:21
|
LL | pub impl(in self::f) trait L1 {}
| ^^^^^^^

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:38:21
|
LL | pub impl(in super::h) trait L3 {}
| ^^^^^^^^

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:47:13
|
LL | pub impl(in crate::a) trait T13 {}
| ^^^^^^^^

error[E0433]: too many leading `super` keywords
--> $DIR/restriction_resolution_errors.rs:54:10
|
LL | pub impl(super) trait T17 {}
| ^^^^^ there are too many leading `super` keywords

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:57:13
|
LL | pub impl(in crate::j) trait L4 {}
| ^^^^^^^^

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:73:21
|
LL | pub impl(in crate::m2) trait U2 {}
| ^^^^^^^^^

error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:75:21
|
LL | pub impl(in m6::m5) trait U4 {}
| ^^^^^^

error[E0433]: cannot find module or crate `a` in this scope
--> $DIR/restriction_resolution_errors.rs:12:21
|
LL | pub impl(in a::b) trait T1 {}
| ^ use of unresolved module or unlinked crate `a`
|
help: there is a crate or module with a similar name
|
LL - pub impl(in a::b) trait T1 {}
LL + pub impl(in c::b) trait T1 {}
|
help: consider importing this module
|
LL + use a;
|

error[E0433]: cannot find module `c` in the crate root
--> $DIR/restriction_resolution_errors.rs:20:28
|
LL | pub impl(in crate::c) trait T5 {}
| ^ not found in the crate root

error[E0577]: expected module, found enum `super::E`
--> $DIR/restriction_resolution_errors.rs:22:21
|
LL | pub impl(in super::E) trait T6 {}
| ^^^^^^^^ not a module

error[E0577]: expected module, found enum `super::G`
--> $DIR/restriction_resolution_errors.rs:36:21
|
LL | pub impl(in super::G) trait L2 {}
| ^^^^^^^^ not a module

error[E0577]: expected module, found enum `crate::a::E`
--> $DIR/restriction_resolution_errors.rs:49:13
|
LL | pub mod b {
| --------- similarly named module `b` defined here
...
LL | pub impl(in crate::a::E) trait T14 {}
| ^^^^^^^^^^^
|
help: a module with a similar name exists
|
LL - pub impl(in crate::a::E) trait T14 {}
LL + pub impl(in crate::a::b) trait T14 {}
|

error[E0577]: expected module, found enum `crate::I`
--> $DIR/restriction_resolution_errors.rs:59:13
|
LL | pub mod a {
| --------- similarly named module `a` defined here
...
LL | pub impl(in crate::I) trait L5 {}
| ^^^^^^^^
|
help: a module with a similar name exists
|
LL - pub impl(in crate::I) trait L5 {}
LL + pub impl(in crate::a) trait L5 {}
|

error[E0577]: expected module, found enum `m7`
--> $DIR/restriction_resolution_errors.rs:76:21
|
LL | pub impl(in m7) trait U5 {}
| ^^ not a module

error: aborting due to 18 previous errors

Some errors have detailed explanations: E0433, E0577.
For more information about an error, try `rustc --explain E0433`.
Loading