Skip to content

Commit 71a3fc3

Browse files
committed
Auto merge of #49789 - petrochenkov:prelext, r=<try>
Module experiments: Add one more prelude layer for extern crate names passed with `--extern` Implements one item from https://internals.rust-lang.org/t/the-great-module-adventure-continues/6678/183 When some name is looked up in lexical scope (`name`, i.e. not module-relative scope `some_mod::name` or `::name`), it's searched roughly in the next order: - local variables - items in unnamed blocks - items in the current module - ✨ NEW! ✨ crate names passed with `--extern` ("extern prelude") - standard library prelude (`Vec`, `drop`) - language prelude (built-in types like `u8`, `str`, etc) The last two layers contain a limited set of names controlled by us and not arbitrary user-defined names like upper layers. We want to be able to add new names into these two layers without breaking user code, so "extern prelude" names have higher priority than std prelude and built-in types. This is a one-time breaking change, that's why it would be nice to run this through crater. Practical impact is expected to be minimal though due to stylistic reasons (there are not many `Uppercase` crates) and due to the way how primitive types are resolved (#32131).
2 parents 7f3444e + c1492fe commit 71a3fc3

13 files changed

+204
-8
lines changed

src/librustc_resolve/lib.rs

+29-7
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,7 @@ pub struct Resolver<'a> {
14071407
graph_root: Module<'a>,
14081408

14091409
prelude: Option<Module<'a>>,
1410+
extern_prelude: FxHashSet<Name>,
14101411

14111412
/// n.b. This is used only for better diagnostics, not name resolution itself.
14121413
has_self: FxHashSet<DefId>,
@@ -1715,6 +1716,7 @@ impl<'a> Resolver<'a> {
17151716
// AST.
17161717
graph_root,
17171718
prelude: None,
1719+
extern_prelude: session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect(),
17181720

17191721
has_self: FxHashSet(),
17201722
field_names: FxHashMap(),
@@ -1970,13 +1972,32 @@ impl<'a> Resolver<'a> {
19701972
}
19711973
}
19721974

1973-
match self.prelude {
1974-
Some(prelude) if !module.no_implicit_prelude => {
1975-
self.resolve_ident_in_module_unadjusted(prelude, ident, ns, false, false, path_span)
1976-
.ok().map(LexicalScopeBinding::Item)
1975+
if !module.no_implicit_prelude {
1976+
// `record_used` means that we don't try to load crates during speculative resolution
1977+
if record_used && ns == TypeNS && self.extern_prelude.contains(&ident.name) {
1978+
if !self.session.features_untracked().extern_prelude {
1979+
feature_err(&self.session.parse_sess, "extern_prelude",
1980+
ident.span, GateIssue::Language,
1981+
"access to extern crates through prelude is experimental").emit();
1982+
}
1983+
1984+
let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
1985+
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
1986+
self.populate_module_if_necessary(crate_root);
1987+
1988+
let binding = (crate_root, ty::Visibility::Public,
1989+
ident.span, Mark::root()).to_name_binding(self.arenas);
1990+
return Some(LexicalScopeBinding::Item(binding));
1991+
}
1992+
if let Some(prelude) = self.prelude {
1993+
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
1994+
false, false, path_span) {
1995+
return Some(LexicalScopeBinding::Item(binding));
1996+
}
19771997
}
1978-
_ => None,
19791998
}
1999+
2000+
None
19802001
}
19812002

19822003
fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, span: &mut Span)
@@ -3587,8 +3608,9 @@ impl<'a> Resolver<'a> {
35873608
// We can see through blocks
35883609
} else {
35893610
// Items from the prelude
3590-
if let Some(prelude) = self.prelude {
3591-
if !module.no_implicit_prelude {
3611+
if !module.no_implicit_prelude {
3612+
names.extend(self.extern_prelude.iter().cloned());
3613+
if let Some(prelude) = self.prelude {
35923614
add_module_candidates(prelude, &mut names);
35933615
}
35943616
}

src/libsyntax/feature_gate.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ declare_features! (
397397
(active, generic_associated_types, "1.23.0", Some(44265), None),
398398

399399
// Resolve absolute paths as paths from other crates
400-
(active, extern_absolute_paths, "1.24.0", Some(44660), None),
400+
(active, extern_absolute_paths, "1.24.0", Some(44660), Some(Edition::Edition2018)),
401401

402402
// `foo.rs` as an alternative to `foo/mod.rs`
403403
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
@@ -466,6 +466,9 @@ declare_features! (
466466

467467
// #[doc(alias = "...")]
468468
(active, doc_alias, "1.27.0", Some(50146), None),
469+
470+
// Access to crate names passed via `--extern` through prelude
471+
(active, extern_prelude, "1.27.0", Some(44660), Some(Edition::Edition2018)),
469472
);
470473

471474
declare_features! (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) ep-lib.rs
5+
$(RUSTC) ep-vec.rs
6+
7+
$(RUSTC) basic.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib
8+
$(RUSTC) shadow-mod.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib
9+
$(RUSTC) shadow-prelude.rs --extern Vec=$(TMPDIR)/libep_vec.rlib
10+
$(RUSTC) feature-gate.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "access to extern crates through prelude is experimental"
11+
$(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "unresolved import"
12+
$(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "failed to resolve"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(extern_prelude)]
12+
13+
fn main() {
14+
let s = ep_lib::S; // It works
15+
s.external();
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "rlib"]
12+
13+
pub struct S;
14+
15+
impl S {
16+
pub fn external(&self) {}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "rlib"]
12+
13+
pub fn new(arg1: f32, arg2: ()) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let s = ep_lib::S; // Feature error
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Extern prelude names are not available by absolute paths
12+
13+
#![feature(extern_prelude)]
14+
15+
use ep_lib::S;
16+
17+
fn main() {
18+
let s = ::ep_lib::S;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Local module shadows `ep_lib` from extern prelude
12+
13+
mod ep_lib {
14+
pub struct S;
15+
16+
impl S {
17+
pub fn internal(&self) {}
18+
}
19+
}
20+
21+
fn main() {
22+
let s = ep_lib::S;
23+
s.internal(); // OK
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Extern prelude shadows standard library prelude
12+
13+
#![feature(extern_prelude)]
14+
15+
fn main() {
16+
let x = Vec::new(0f32, ()); // OK
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere
12+
13+
mod m {
14+
pub struct LooksLikeExternCrate;
15+
}
16+
17+
fn main() {
18+
// OK, speculative resolution for `unused_qualifications` doesn't try
19+
// to resolve this as an extern crate and load that crate
20+
let s = m::LooksLikeExternCrate {};
21+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected one of `!` or `::`, found `-`
2+
--> $DIR/feature-gate-extern_prelude.rs:11:4
3+
|
4+
LL | can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-`
5+
| ^ expected one of `!` or `::` here
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)