resolve: Support imports of associated types and glob imports from traits

This commit is contained in:
Vadim Petrochenkov 2025-03-19 16:11:45 +03:00
parent db074a06fe
commit 3eee3dad5c
20 changed files with 168 additions and 113 deletions

View file

@ -1,9 +1,13 @@
#### Note: this error code is no longer emitted by the compiler.
Attempt was made to import an unimportable type. This can happen when trying
to import a type from a trait.
Erroneous code example:
```compile_fail,E0253
```
#![feature(import_trait_associated_functions)]
mod foo {
pub trait MyTrait {
type SomeType;

View file

@ -1770,7 +1770,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
) -> Ty<'tcx> {
match self.lower_qpath_shared(
@ -1795,7 +1795,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
) -> Const<'tcx> {
match self.lower_qpath_shared(
@ -1820,7 +1820,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
@ -1840,7 +1840,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?self_ty);
let trait_ref =
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment.unwrap(), false);
debug!(?trait_ref);
let item_args =
@ -2196,16 +2196,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
Some(trait_)
} else {
None
};
self.lower_qpath_ty(
span,
opt_self_ty,
def_id,
&path.segments[path.segments.len() - 2],
trait_segment,
path.segments.last().unwrap(),
)
}
@ -2413,16 +2414,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::AssocConst, did) => {
debug_assert!(path.segments.len() >= 2);
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
Some(trait_)
} else {
None
};
self.lower_qpath_const(
span,
opt_self_ty,
did,
&path.segments[path.segments.len() - 2],
trait_segment,
path.segments.last().unwrap(),
)
}

View file

@ -218,10 +218,6 @@ resolve_invalid_asm_sym =
.label = is a local variable
.help = `sym` operands must refer to either a function or a static
resolve_is_not_directly_importable =
`{$target}` is not directly importable
.label = cannot be imported directly
resolve_is_private =
{$ident_descr} `{$ident}` is private
.label = private {$ident_descr}
@ -231,9 +227,6 @@ resolve_item_was_behind_feature =
resolve_item_was_cfg_out = the item is gated here
resolve_items_in_traits_are_not_importable =
items in traits are not importable
resolve_label_with_similar_name_reachable =
a label with a similar name is reachable

View file

@ -1181,11 +1181,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} {
let in_module_is_extern = !in_module.def_id().is_local();
in_module.for_each_child(self, |this, ident, ns, name_binding| {
// avoid non-importable candidates
if !name_binding.is_importable()
// FIXME(import_trait_associated_functions): remove this when `import_trait_associated_functions` is stable
|| name_binding.is_assoc_const_or_fn()
&& !this.tcx.features().import_trait_associated_functions()
// Avoid non-importable candidates.
if name_binding.is_assoc_item()
&& !this.tcx.features().import_trait_associated_functions()
{
return;
}

View file

@ -781,22 +781,6 @@ pub(crate) struct CannotGlobImportAllCrates {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(resolve_items_in_traits_are_not_importable)]
pub(crate) struct ItemsInTraitsAreNotImportable {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(resolve_is_not_directly_importable, code = E0253)]
pub(crate) struct IsNotDirectlyImportable {
#[primary_span]
#[label]
pub(crate) span: Span,
pub(crate) target: Ident,
}
#[derive(Subdiagnostic)]
#[suggestion(
resolve_unexpected_res_change_ty_to_const_param_sugg,

View file

@ -30,8 +30,7 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates};
use crate::errors::{
CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
ConsiderAddingMacroExport, ConsiderMarkingAsPub, IsNotDirectlyImportable,
ItemsInTraitsAreNotImportable,
ConsiderAddingMacroExport, ConsiderMarkingAsPub,
};
use crate::{
AmbiguityError, AmbiguityKind, BindingKey, Finalize, ImportSuggestion, Module,
@ -835,11 +834,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let parent = import.parent_scope.module;
match source_bindings[ns].get() {
Err(Undetermined) => indeterminate_count += 1,
// Don't update the resolution, because it was never added.
Err(Determined) if target.name == kw::Underscore => {}
Ok(binding) if binding.is_importable() => {
if binding.is_assoc_const_or_fn()
Ok(binding) => {
if binding.is_assoc_item()
&& !this.tcx.features().import_trait_associated_functions()
{
feature_err(
@ -850,21 +846,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
)
.emit();
}
let imported_binding = this.import(binding, import);
target_bindings[ns].set(Some(imported_binding));
this.define(parent, target, ns, imported_binding);
}
source_binding @ (Ok(..) | Err(Determined)) => {
if source_binding.is_ok() {
this.dcx()
.create_err(IsNotDirectlyImportable { span: import.span, target })
.emit();
Err(Determined) => {
// Don't update the resolution for underscores, because it was never added.
if target.name != kw::Underscore {
let key = BindingKey::new(target, ns);
this.update_resolution(parent, key, false, |_, resolution| {
resolution.single_imports.swap_remove(&import);
});
}
let key = BindingKey::new(target, ns);
this.update_resolution(parent, key, false, |_, resolution| {
resolution.single_imports.swap_remove(&import);
});
}
Err(Undetermined) => indeterminate_count += 1,
}
}
});
@ -1428,10 +1424,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
return;
};
if module.is_trait() {
self.dcx().emit_err(ItemsInTraitsAreNotImportable { span: import.span });
return;
} else if module == import.parent_scope.module {
if module.is_trait() && !self.tcx.features().import_trait_associated_functions() {
feature_err(
self.tcx.sess,
sym::import_trait_associated_functions,
import.span,
"`use` associated items of traits is unstable",
)
.emit();
}
if module == import.parent_scope.module {
return;
} else if is_prelude {
self.prelude = Some(module);

View file

@ -949,14 +949,8 @@ impl<'ra> NameBindingData<'ra> {
}
}
fn is_importable(&self) -> bool {
!matches!(self.res(), Res::Def(DefKind::AssocTy, _))
}
// FIXME(import_trait_associated_functions): associate `const` or `fn` are not importable unless
// the feature `import_trait_associated_functions` is enable
fn is_assoc_const_or_fn(&self) -> bool {
matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn, _))
fn is_assoc_item(&self) -> bool {
matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _))
}
fn macro_kind(&self) -> Option<MacroKind> {

View file

@ -1,10 +0,0 @@
mod foo {
pub trait MyTrait {
type SomeType;
}
}
use foo::MyTrait::SomeType;
//~^ ERROR E0253
fn main() {}

View file

@ -1,9 +0,0 @@
error[E0253]: `SomeType` is not directly importable
--> $DIR/E0253.rs:7:5
|
LL | use foo::MyTrait::SomeType;
| ^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0253`.

View file

@ -60,4 +60,7 @@ fn f() {
let t: Option<S> = DEFAULT;
}
trait Glob {}
use Glob::*; //~ ERROR `use` associated items of traits is unstable
fn main() {}

View file

@ -48,6 +48,16 @@ LL | use super::A::{self, DEFAULT, new};
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 5 previous errors
error[E0658]: `use` associated items of traits is unstable
--> $DIR/feature-gate-import-trait-associated-functions.rs:64:5
|
LL | use Glob::*;
| ^^^^^^^
|
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -3,7 +3,4 @@ use Alias::*; //~ ERROR unresolved import `Alias` [E0432]
use std::io::Result::*; //~ ERROR unresolved import `std::io::Result` [E0432]
trait T {}
use T::*; //~ ERROR items in traits are not importable
fn main() {}

View file

@ -1,9 +1,3 @@
error: items in traits are not importable
--> $DIR/issue-30560.rs:7:5
|
LL | use T::*;
| ^^^^
error[E0432]: unresolved import `Alias`
--> $DIR/issue-30560.rs:2:5
|
@ -16,6 +10,6 @@ error[E0432]: unresolved import `std::io::Result`
LL | use std::io::Result::*;
| ^^^^^^ `Result` is a type alias, not a module
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0432`.

View file

@ -0,0 +1,18 @@
#![feature(import_trait_associated_functions)]
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
trait Trait {
type AssocTy;
const CONST: usize;
}
use Trait::AssocTy;
type Alias1 = AssocTy; //~ ERROR ambiguous associated type
type Alias2 = self::AssocTy; //~ ERROR ambiguous associated type
use Trait::CONST;
type Alias3 = [u8; CONST]; //~ ERROR ambiguous associated constant
type Alias4 = [u8; self::CONST]; //~ ERROR ambiguous associated constant
fn main() {}

View file

@ -0,0 +1,49 @@
error[E0223]: ambiguous associated type
--> $DIR/import_trait_associated_item_bad.rs:11:15
|
LL | type Alias1 = AssocTy;
| ^^^^^^^
|
help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
|
LL | type Alias1 = <Example as Trait>::AssocTy;
| ++++++++++++++++++++
error[E0223]: ambiguous associated type
--> $DIR/import_trait_associated_item_bad.rs:12:15
|
LL | type Alias2 = self::AssocTy;
| ^^^^^^^^^^^^^
|
help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
|
LL - type Alias2 = self::AssocTy;
LL + type Alias2 = <Example as Trait>::AssocTy;
|
error[E0223]: ambiguous associated constant
--> $DIR/import_trait_associated_item_bad.rs:15:20
|
LL | type Alias3 = [u8; CONST];
| ^^^^^
|
help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
|
LL | type Alias3 = [u8; <Example as Trait>::CONST];
| ++++++++++++++++++++
error[E0223]: ambiguous associated constant
--> $DIR/import_trait_associated_item_bad.rs:16:20
|
LL | type Alias4 = [u8; self::CONST];
| ^^^^^^^^^^^
|
help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
|
LL - type Alias4 = [u8; self::CONST];
LL + type Alias4 = [u8; <Example as Trait>::CONST];
|
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0223`.

View file

@ -0,0 +1,17 @@
//@ check-pass
#![feature(import_trait_associated_functions)]
trait Trait: Default {
fn f() -> Self { Default::default() }
fn g() -> Self { Default::default() }
}
impl Trait for u8 {}
use Trait::*;
fn main() {
let _: u8 = f();
let _: u8 = g();
}

View file

@ -6,7 +6,7 @@ use use_from_trait_xc::Trait::foo;
//~^ ERROR `use` associated items of traits is unstable [E0658]
use use_from_trait_xc::Trait::Assoc;
//~^ ERROR `Assoc` is not directly importable
//~^ ERROR `use` associated items of traits is unstable [E0658]
use use_from_trait_xc::Trait::CONST;
//~^ ERROR `use` associated items of traits is unstable [E0658]

View file

@ -8,11 +8,15 @@ LL | use use_from_trait_xc::Trait::foo;
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0253]: `Assoc` is not directly importable
error[E0658]: `use` associated items of traits is unstable
--> $DIR/use-from-trait-xc.rs:8:5
|
LL | use use_from_trait_xc::Trait::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `use` associated items of traits is unstable
--> $DIR/use-from-trait-xc.rs:11:5
@ -74,5 +78,5 @@ LL | struct Foo;
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0253, E0432, E0603, E0658.
For more information about an error, try `rustc --explain E0253`.
Some errors have detailed explanations: E0432, E0603, E0658.
For more information about an error, try `rustc --explain E0432`.

View file

@ -1,5 +1,5 @@
use Trait::foo; //~ ERROR `use` associated items of traits is unstable [E0658]
use Trait::Assoc; //~ ERROR `Assoc` is not directly importable
use Trait::Assoc; //~ ERROR `use` associated items of traits is unstable [E0658]
use Trait::C; //~ ERROR `use` associated items of traits is unstable [E0658]
use Foo::new; //~ ERROR unresolved import `Foo` [E0432]

View file

@ -8,11 +8,15 @@ LL | use Trait::foo;
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0253]: `Assoc` is not directly importable
error[E0658]: `use` associated items of traits is unstable
--> $DIR/use-from-trait.rs:2:5
|
LL | use Trait::Assoc;
| ^^^^^^^^^^^^ cannot be imported directly
| ^^^^^^^^^^^^
|
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `use` associated items of traits is unstable
--> $DIR/use-from-trait.rs:3:5
@ -38,5 +42,5 @@ LL | use Foo::C2;
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0253, E0432, E0658.
For more information about an error, try `rustc --explain E0253`.
Some errors have detailed explanations: E0432, E0658.
For more information about an error, try `rustc --explain E0432`.