Skip to content

Commit

Permalink
Implement use associated items of traits
Browse files Browse the repository at this point in the history
  • Loading branch information
frank-king committed Jan 16, 2025
1 parent 4e5fec2 commit 5079acc
Show file tree
Hide file tree
Showing 21 changed files with 374 additions and 42 deletions.
12 changes: 6 additions & 6 deletions compiler/rustc_error_codes/src/error_codes/E0253.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
Attempt was made to import an unimportable value. This can happen when trying
to import a method from a trait.
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
mod foo {
pub trait MyTrait {
fn do_something();
type SomeType;
}
}
use foo::MyTrait::do_something;
// error: `do_something` is not directly importable
use foo::MyTrait::SomeType;
// error: `SomeType` is not directly importable
fn main() {}
```

It's invalid to directly import methods belonging to a trait or concrete type.
It's invalid to directly import types belonging to a trait.
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@ declare_features! (
(unstable, impl_trait_in_bindings, "1.64.0", Some(63065)),
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
(unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)),
/// Allows `use` associated functions from traits.
(unstable, import_trait_associated_functions, "CURRENT_RUSTC_VERSION", Some(134691)),
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995)),
/// Allow anonymous constants from an inline `const` block in pattern position
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,7 +1183,11 @@ 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() {
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()
{
return;
}

Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ use rustc_session::lint::builtin::{
AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE,
REDUNDANT_IMPORTS, UNUSED_IMPORTS,
};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::hygiene::LocalExpnId;
use rustc_span::{Ident, Span, Symbol, kw};
use rustc_span::{Ident, Span, Symbol, kw, sym};
use smallvec::SmallVec;
use tracing::debug;

Expand Down Expand Up @@ -829,6 +830,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// 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()
&& !this.tcx.features().import_trait_associated_functions()
{
feature_err(
this.tcx.sess,
sym::import_trait_associated_functions,
import.span,
"`use` associated items of traits is unstable",
)
.emit();
}
let imported_binding = this.import(binding, import);
target_bindings[ns].set(Some(imported_binding));
this.define(parent, target, ns, imported_binding);
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,10 +920,13 @@ impl<'ra> NameBindingData<'ra> {
}

fn is_importable(&self) -> bool {
!matches!(
self.res(),
Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _)
)
!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 macro_kind(&self) -> Option<MacroKind> {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ symbols! {
import,
import_name_type,
import_shadowing,
import_trait_associated_functions,
imported_main,
in_band_lifetimes,
include,
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/error-codes/E0253.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
mod foo {
pub trait MyTrait {
fn do_something();
type SomeType;
}
}

use foo::MyTrait::do_something;
use foo::MyTrait::SomeType;
//~^ ERROR E0253

fn main() {}
6 changes: 3 additions & 3 deletions tests/ui/error-codes/E0253.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0253]: `do_something` is not directly importable
error[E0253]: `SomeType` is not directly importable
--> $DIR/E0253.rs:7:5
|
LL | use foo::MyTrait::do_something;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly
LL | use foo::MyTrait::SomeType;
| ^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//@ edition:2018
use std::collections::HashMap;

use A::{DEFAULT, new};
//~^ ERROR `use` associated items of traits is unstable [E0658]
//~| ERROR `use` associated items of traits is unstable [E0658]
use Default::default;
//~^ ERROR `use` associated items of traits is unstable [E0658]

struct S {
a: HashMap<i32, i32>,
}

impl S {
fn new() -> S {
S { a: default() }
}
}

trait A: Sized {
const DEFAULT: Option<Self> = None;
fn new() -> Self;
fn do_something(&self);
}

mod b {
use super::A::{self, DEFAULT, new};
//~^ ERROR `use` associated items of traits is unstable [E0658]
//~| ERROR `use` associated items of traits is unstable [E0658]

struct B();

impl A for B {
const DEFAULT: Option<Self> = Some(B());
fn new() -> Self {
B()
}

fn do_something(&self) {}
}

fn f() {
let b: B = new();
b.do_something();
let c: B = DEFAULT.unwrap();
}
}

impl A for S {
fn new() -> Self {
S::new()
}

fn do_something(&self) {}
}

fn f() {
let s: S = new();
s.do_something();
let t: Option<S> = DEFAULT;
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
error[E0658]: `use` associated items of traits is unstable
--> $DIR/feature-gate-import-trait-associated-functions.rs:4:9
|
LL | use A::{DEFAULT, new};
| ^^^^^^^
|
= 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/feature-gate-import-trait-associated-functions.rs:4:18
|
LL | use A::{DEFAULT, new};
| ^^^
|
= 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/feature-gate-import-trait-associated-functions.rs:7:5
|
LL | use Default::default;
| ^^^^^^^^^^^^^^^^
|
= 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/feature-gate-import-trait-associated-functions.rs:27:26
|
LL | use super::A::{self, DEFAULT, new};
| ^^^^^^^
|
= 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/feature-gate-import-trait-associated-functions.rs:27:35
|
LL | use super::A::{self, DEFAULT, new};
| ^^^
|
= 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 5 previous errors

For more information about this error, try `rustc --explain E0658`.
4 changes: 2 additions & 2 deletions tests/ui/imports/import-trait-method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ trait Foo {
fn foo();
}

use Foo::foo; //~ ERROR not directly importable
use Foo::foo; //~ ERROR `use` associated items of traits is unstable [E0658]

fn main() { foo(); }
fn main() { foo(); } //~ ERROR type annotations needed
21 changes: 17 additions & 4 deletions tests/ui/imports/import-trait-method.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
error[E0253]: `foo` is not directly importable
error[E0658]: `use` associated items of traits is unstable
--> $DIR/import-trait-method.rs:5:5
|
LL | use Foo::foo;
| ^^^^^^^^ 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[E0283]: type annotations needed
--> $DIR/import-trait-method.rs:7:13
|
LL | fn main() { foo(); }
| ^^^^^ cannot infer type
|
= note: cannot satisfy `_: Foo`

error: aborting due to 1 previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0253`.
Some errors have detailed explanations: E0283, E0658.
For more information about an error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error[E0425]: cannot find function `cmp` in this scope
--> $DIR/fn-to-method.rs:12:13
|
LL | let x = cmp(&1, &2);
| ^^^ not found in this scope
|
help: consider importing one of these associated functions
|
LL + use std::cmp::Ord::cmp;
|
LL + use std::iter::Iterator::cmp;
|

error[E0425]: cannot find function `len` in this scope
--> $DIR/fn-to-method.rs:16:13
|
LL | let y = len([1, 2, 3]);
| ^^^ not found in this scope
|
help: consider importing this associated function
|
LL + use std::iter::ExactSizeIterator::len;
|

error[E0425]: cannot find function `bar` in this scope
--> $DIR/fn-to-method.rs:20:13
|
LL | let z = bar(Foo);
| ^^^ not found in this scope
|
help: use the `.` operator to call the method `bar` on `Foo`
|
LL - let z = bar(Foo);
LL + let z = Foo.bar();
|

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0425`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0425]: cannot find function `cmp` in this scope
--> $DIR/fn-to-method.rs:8:13
--> $DIR/fn-to-method.rs:12:13
|
LL | let x = cmp(&1, &2);
| ^^^ not found in this scope
Expand All @@ -10,7 +10,7 @@ LL | let x = (&1).cmp(&2);
| ~ ~~~~~~~~~

error[E0425]: cannot find function `len` in this scope
--> $DIR/fn-to-method.rs:12:13
--> $DIR/fn-to-method.rs:16:13
|
LL | let y = len([1, 2, 3]);
| ^^^ not found in this scope
Expand All @@ -22,7 +22,7 @@ LL + let y = [1, 2, 3].len();
|

error[E0425]: cannot find function `bar` in this scope
--> $DIR/fn-to-method.rs:16:13
--> $DIR/fn-to-method.rs:20:13
|
LL | let z = bar(Foo);
| ^^^ not found in this scope
Expand Down
8 changes: 6 additions & 2 deletions tests/ui/suggestions/fn-to-method.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//@ revisions: normal import_trait_associated_functions
#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
struct Foo;
//[import_trait_associated_functions]~^ HELP consider importing one of these associated functions
//[import_trait_associated_functions]~| HELP consider importing this associated function

impl Foo {
fn bar(self) {}
Expand All @@ -7,11 +11,11 @@ impl Foo {
fn main() {
let x = cmp(&1, &2);
//~^ ERROR cannot find function `cmp` in this scope
//~| HELP use the `.` operator to call the method `Ord::cmp` on `&{integer}`
//[normal]~| HELP use the `.` operator to call the method `Ord::cmp` on `&{integer}`

let y = len([1, 2, 3]);
//~^ ERROR cannot find function `len` in this scope
//~| HELP use the `.` operator to call the method `len` on `&[{integer}]`
//[normal]~| HELP use the `.` operator to call the method `len` on `&[{integer}]`

let z = bar(Foo);
//~^ ERROR cannot find function `bar` in this scope
Expand Down
Loading

0 comments on commit 5079acc

Please sign in to comment.