Auto merge of #65454 - tmandry:rollup-0k6jiik, r=tmandry
Rollup of 14 pull requests Successful merges: - #64603 (Reducing spurious unused lifetime warnings.) - #64623 (Remove last uses of gensyms) - #65235 (don't assume we can *always* find a return type hint in async fn) - #65242 (Fix suggestion to constrain trait for method to be found) - #65265 (Cleanup librustc mir err codes) - #65293 (Optimize `try_expand_impl_trait_type`) - #65307 (Try fix incorrect "explicit lifetime name needed") - #65308 (Add long error explanation for E0574) - #65353 (save-analysis: Don't ICE when resolving qualified type paths in struct members) - #65389 (Return `false` from `needs_drop` for all zero-sized arrays.) - #65402 (Add troubleshooting section to PGO chapter in rustc book.) - #65425 (Optimize `BitIter`) - #65438 (Organize `never_type` tests) - #65444 (Implement AsRef<[T]> for List<T>) Failed merges: - #65390 (Add long error explanation for E0576) r? @ghost
This commit is contained in:
commit
f54911c6f2
99 changed files with 1096 additions and 508 deletions
|
@ -125,6 +125,17 @@ RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
|
|||
cargo build --release --target=x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- It is recommended to pass `-Cllvm-args=-pgo-warn-missing-function` during the
|
||||
`-Cprofile-use` phase. LLVM by default does not warn if it cannot find
|
||||
profiling data for a given function. Enabling this warning will make it
|
||||
easier to spot errors in your setup.
|
||||
|
||||
- There is a [known issue](https://github.com/rust-lang/cargo/issues/7416) in
|
||||
Cargo prior to version 1.39 that will prevent PGO from working correctly. Be
|
||||
sure to use Cargo 1.39 or newer when doing PGO.
|
||||
|
||||
## Further Reading
|
||||
|
||||
`rustc`'s PGO support relies entirely on LLVM's implementation of the feature
|
||||
|
|
|
@ -3291,10 +3291,14 @@ impl<'a> LoweringContext<'a> {
|
|||
let id = self.sess.next_node_id();
|
||||
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
|
||||
}
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
|
||||
// `PassThrough` is the normal case.
|
||||
// `new_error_lifetime`, which would usually be used in the case of `ReportError`,
|
||||
// is unsuitable here, as these can occur from missing lifetime parameters in a
|
||||
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
|
||||
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
|
||||
// later, at which point a suitable error will be emitted.
|
||||
| AnonymousLifetimeMode::PassThrough
|
||||
| AnonymousLifetimeMode::ReportError => self.new_implicit_lifetime(span),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -708,15 +708,22 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m);
|
||||
let def_id = if let Region::EarlyBound(_ ,def_id , _) = reg {
|
||||
def_id
|
||||
} else {
|
||||
bug!();
|
||||
};
|
||||
if let hir::ParamName::Plain(param_name) = name {
|
||||
if param_name.name == kw::UnderscoreLifetime {
|
||||
// Pick the elided lifetime "definition" if one exists
|
||||
// and use it to make an elision scope.
|
||||
self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many);
|
||||
elision = Some(reg);
|
||||
} else {
|
||||
lifetimes.insert(name, reg);
|
||||
}
|
||||
} else {
|
||||
self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many);
|
||||
lifetimes.insert(name, reg);
|
||||
}
|
||||
}
|
||||
|
@ -1615,7 +1622,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
_ => None,
|
||||
} {
|
||||
debug!("id = {:?} span = {:?} name = {:?}", id, span, name);
|
||||
|
||||
if name.name == kw::UnderscoreLifetime {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -701,6 +701,13 @@ impl<T> Deref for List<T> {
|
|||
type Target = [T];
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &[T] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<[T]> for List<T> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &[T] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.data.as_ptr(), self.len)
|
||||
}
|
||||
|
|
|
@ -1483,7 +1483,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
|
|||
}
|
||||
|
||||
// Replace any anonymous late-bound regions with named
|
||||
// variants, using gensym'd identifiers, so that we can
|
||||
// variants, using new unique identifiers, so that we can
|
||||
// clearly differentiate between named and unnamed regions in
|
||||
// the output. We'll probably want to tweak this over time to
|
||||
// decide just how much information to give.
|
||||
|
|
|
@ -697,6 +697,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// that type, and when we finish expanding that type we remove the
|
||||
// its DefId.
|
||||
seen_opaque_tys: FxHashSet<DefId>,
|
||||
// Cache of all expansions we've seen so far. This is a critical
|
||||
// optimization for some large types produced by async fn trees.
|
||||
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
|
||||
primary_def_id: DefId,
|
||||
found_recursion: bool,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -713,9 +716,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
let substs = substs.fold_with(self);
|
||||
if self.seen_opaque_tys.insert(def_id) {
|
||||
let generic_ty = self.tcx.type_of(def_id);
|
||||
let concrete_ty = generic_ty.subst(self.tcx, substs);
|
||||
let expanded_ty = self.fold_ty(concrete_ty);
|
||||
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
|
||||
Some(expanded_ty) => expanded_ty,
|
||||
None => {
|
||||
let generic_ty = self.tcx.type_of(def_id);
|
||||
let concrete_ty = generic_ty.subst(self.tcx, substs);
|
||||
let expanded_ty = self.fold_ty(concrete_ty);
|
||||
self.expanded_cache.insert((def_id, substs), expanded_ty);
|
||||
expanded_ty
|
||||
}
|
||||
};
|
||||
self.seen_opaque_tys.remove(&def_id);
|
||||
Some(expanded_ty)
|
||||
} else {
|
||||
|
@ -735,14 +745,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let ty::Opaque(def_id, substs) = t.kind {
|
||||
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
|
||||
} else {
|
||||
} else if t.has_projections() {
|
||||
t.super_fold_with(self)
|
||||
} else {
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = OpaqueTypeExpander {
|
||||
seen_opaque_tys: FxHashSet::default(),
|
||||
expanded_cache: FxHashMap::default(),
|
||||
primary_def_id: def_id,
|
||||
found_recursion: false,
|
||||
tcx: self,
|
||||
|
@ -1096,6 +1109,9 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
|
|||
|
||||
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
|
||||
|
||||
// Zero-length arrays never contain anything to drop.
|
||||
ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
|
||||
|
||||
// Structural recursion.
|
||||
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
|
||||
|
||||
|
|
|
@ -168,11 +168,7 @@ impl<T: Idx> BitSet<T> {
|
|||
/// Iterates over the indices of set bits in a sorted order.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> BitIter<'_, T> {
|
||||
BitIter {
|
||||
cur: None,
|
||||
iter: self.words.iter().enumerate(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
BitIter::new(&self.words)
|
||||
}
|
||||
|
||||
/// Duplicates the set as a hybrid set.
|
||||
|
@ -291,26 +287,55 @@ impl<T: Idx> ToString for BitSet<T> {
|
|||
}
|
||||
|
||||
pub struct BitIter<'a, T: Idx> {
|
||||
cur: Option<(Word, usize)>,
|
||||
iter: iter::Enumerate<slice::Iter<'a, Word>>,
|
||||
/// A copy of the current word, but with any already-visited bits cleared.
|
||||
/// (This lets us use `trailing_zeros()` to find the next set bit.) When it
|
||||
/// is reduced to 0, we move onto the next word.
|
||||
word: Word,
|
||||
|
||||
/// The offset (measured in bits) of the current word.
|
||||
offset: usize,
|
||||
|
||||
/// Underlying iterator over the words.
|
||||
iter: slice::Iter<'a, Word>,
|
||||
|
||||
marker: PhantomData<T>
|
||||
}
|
||||
|
||||
impl<'a, T: Idx> BitIter<'a, T> {
|
||||
#[inline]
|
||||
fn new(words: &'a [Word]) -> BitIter<'a, T> {
|
||||
// We initialize `word` and `offset` to degenerate values. On the first
|
||||
// call to `next()` we will fall through to getting the first word from
|
||||
// `iter`, which sets `word` to the first word (if there is one) and
|
||||
// `offset` to 0. Doing it this way saves us from having to maintain
|
||||
// additional state about whether we have started.
|
||||
BitIter {
|
||||
word: 0,
|
||||
offset: std::usize::MAX - (WORD_BITS - 1),
|
||||
iter: words.iter(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Idx> Iterator for BitIter<'a, T> {
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<T> {
|
||||
loop {
|
||||
if let Some((ref mut word, offset)) = self.cur {
|
||||
let bit_pos = word.trailing_zeros() as usize;
|
||||
if bit_pos != WORD_BITS {
|
||||
let bit = 1 << bit_pos;
|
||||
*word ^= bit;
|
||||
return Some(T::new(bit_pos + offset))
|
||||
}
|
||||
if self.word != 0 {
|
||||
// Get the position of the next set bit in the current word,
|
||||
// then clear the bit.
|
||||
let bit_pos = self.word.trailing_zeros() as usize;
|
||||
let bit = 1 << bit_pos;
|
||||
self.word ^= bit;
|
||||
return Some(T::new(bit_pos + self.offset))
|
||||
}
|
||||
|
||||
let (i, word) = self.iter.next()?;
|
||||
self.cur = Some((*word, WORD_BITS * i));
|
||||
// Move onto the next word. `wrapping_add()` is needed to handle
|
||||
// the degenerate initial value given to `offset` in `new()`.
|
||||
let word = self.iter.next()?;
|
||||
self.word = *word;
|
||||
self.offset = self.offset.wrapping_add(WORD_BITS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -851,11 +876,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
|
|||
pub fn iter(&self, row: R) -> BitIter<'_, C> {
|
||||
assert!(row.index() < self.num_rows);
|
||||
let (start, end) = self.range(row);
|
||||
BitIter {
|
||||
cur: None,
|
||||
iter: self.words[start..end].iter().enumerate(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
BitIter::new(&self.words[start..end])
|
||||
}
|
||||
|
||||
/// Returns the number of elements in `row`.
|
||||
|
|
|
@ -104,25 +104,16 @@ impl<'tcx> TransferFunction<'_, '_, 'tcx> {
|
|||
kind: mir::BorrowKind,
|
||||
borrowed_place: &mir::Place<'tcx>,
|
||||
) -> bool {
|
||||
let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty;
|
||||
|
||||
// Zero-sized types cannot be mutated, since there is nothing inside to mutate.
|
||||
//
|
||||
// FIXME: For now, we only exempt arrays of length zero. We need to carefully
|
||||
// consider the effects before extending this to all ZSTs.
|
||||
if let ty::Array(_, len) = borrowed_ty.kind {
|
||||
if len.try_eval_usize(self.tcx, self.param_env) == Some(0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
match kind {
|
||||
mir::BorrowKind::Mut { .. } => true,
|
||||
|
||||
| mir::BorrowKind::Shared
|
||||
| mir::BorrowKind::Shallow
|
||||
| mir::BorrowKind::Unique
|
||||
=> !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP),
|
||||
=> !borrowed_place
|
||||
.ty(self.body, self.tcx)
|
||||
.ty
|
||||
.is_freeze(self.tcx, self.param_env, DUMMY_SP),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,9 @@ E0004: r##"
|
|||
This error indicates that the compiler cannot guarantee a matching pattern for
|
||||
one or more possible inputs to a match expression. Guaranteed matches are
|
||||
required in order to assign values to match expressions, or alternatively,
|
||||
determine the flow of execution. Erroneous code example:
|
||||
determine the flow of execution.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0004
|
||||
enum Terminator {
|
||||
|
@ -109,7 +111,9 @@ match x {
|
|||
|
||||
E0005: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee
|
||||
that a name will be extracted in all cases. Erroneous code example:
|
||||
that a name will be extracted in all cases.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0005
|
||||
let x = Some(1);
|
||||
|
@ -145,6 +149,8 @@ like the following is invalid as it requires the entire `Option<String>` to be
|
|||
moved into a variable called `op_string` while simultaneously requiring the
|
||||
inner `String` to be moved into a variable called `s`.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0007
|
||||
let x = Some("s".to_string());
|
||||
|
||||
|
@ -208,15 +214,130 @@ match x {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0010: r##"
|
||||
The value of statics and constants must be known at compile time, and they live
|
||||
for the entire lifetime of a program. Creating a boxed value allocates memory on
|
||||
the heap at runtime, and therefore cannot be done at compile time.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0010
|
||||
#![feature(box_syntax)]
|
||||
|
||||
const CON : Box<i32> = box 0;
|
||||
```
|
||||
"##,
|
||||
|
||||
E0013: r##"
|
||||
Static and const variables can refer to other const variables. But a const
|
||||
variable cannot refer to a static variable.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0013
|
||||
static X: i32 = 42;
|
||||
const Y: i32 = X;
|
||||
```
|
||||
|
||||
In this example, `Y` cannot refer to `X` here. To fix this, the value can be
|
||||
extracted as a const and then used:
|
||||
|
||||
```
|
||||
const A: i32 = 42;
|
||||
static X: i32 = A;
|
||||
const Y: i32 = A;
|
||||
```
|
||||
"##,
|
||||
|
||||
// FIXME(#57563) Change the language here when const fn stabilizes
|
||||
E0015: r##"
|
||||
The only functions that can be called in static or constant expressions are
|
||||
`const` functions, and struct/enum constructors. `const` functions are only
|
||||
available on a nightly compiler. Rust currently does not support more general
|
||||
compile-time function execution.
|
||||
|
||||
```
|
||||
const FOO: Option<u8> = Some(1); // enum constructor
|
||||
struct Bar {x: u8}
|
||||
const BAR: Bar = Bar {x: 1}; // struct constructor
|
||||
```
|
||||
|
||||
See [RFC 911] for more details on the design of `const fn`s.
|
||||
|
||||
[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
|
||||
"##,
|
||||
|
||||
E0017: r##"
|
||||
References in statics and constants may only refer to immutable values.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0017
|
||||
static X: i32 = 1;
|
||||
const C: i32 = 2;
|
||||
|
||||
// these three are not allowed:
|
||||
const CR: &mut i32 = &mut C;
|
||||
static STATIC_REF: &'static mut i32 = &mut X;
|
||||
static CONST_REF: &'static mut i32 = &mut C;
|
||||
```
|
||||
|
||||
Statics are shared everywhere, and if they refer to mutable data one might
|
||||
violate memory safety since holding multiple mutable references to shared data
|
||||
is not allowed.
|
||||
|
||||
If you really want global mutable state, try using `static mut` or a global
|
||||
`UnsafeCell`.
|
||||
"##,
|
||||
|
||||
E0019: r##"
|
||||
A function call isn't allowed in the const's initialization expression
|
||||
because the expression's value must be known at compile-time.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0019
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
struct MyOwned;
|
||||
|
||||
static STATIC11: Box<MyOwned> = box MyOwned; // error!
|
||||
}
|
||||
```
|
||||
|
||||
Remember: you can't use a function call inside a const's initialization
|
||||
expression! However, you can totally use it anywhere else:
|
||||
|
||||
```
|
||||
enum Test {
|
||||
V1
|
||||
}
|
||||
|
||||
impl Test {
|
||||
fn func(&self) -> i32 {
|
||||
12
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const FOO: Test = Test::V1;
|
||||
|
||||
FOO.func(); // here is good
|
||||
let x = FOO.func(); // or even here!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0030: r##"
|
||||
When matching against a range, the compiler verifies that the range is
|
||||
non-empty. Range patterns include both end-points, so this is equivalent to
|
||||
non-empty. Range patterns include both end-points, so this is equivalent to
|
||||
requiring the start of the range to be less than or equal to the end of the
|
||||
range.
|
||||
|
||||
For example:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0030
|
||||
match 5u32 {
|
||||
// This range is ok, albeit pointless.
|
||||
1 ..= 1 => {}
|
||||
|
@ -226,7 +347,61 @@ match 5u32 {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0133: r##"
|
||||
Unsafe code was used outside of an unsafe function or block.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0133
|
||||
unsafe fn f() { return; } // This is the unsafe code
|
||||
|
||||
fn main() {
|
||||
f(); // error: call to unsafe function requires unsafe function or block
|
||||
}
|
||||
```
|
||||
|
||||
Using unsafe functionality is potentially dangerous and disallowed by safety
|
||||
checks. Examples:
|
||||
|
||||
* Dereferencing raw pointers
|
||||
* Calling functions via FFI
|
||||
* Calling functions marked unsafe
|
||||
|
||||
These safety checks can be relaxed for a section of the code by wrapping the
|
||||
unsafe instructions with an `unsafe` block. For instance:
|
||||
|
||||
```
|
||||
unsafe fn f() { return; }
|
||||
|
||||
fn main() {
|
||||
unsafe { f(); } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
"##,
|
||||
|
||||
E0158: r##"
|
||||
An associated const has been referenced in a pattern.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0158
|
||||
enum EFoo { A, B, C, D }
|
||||
|
||||
trait Foo {
|
||||
const X: EFoo;
|
||||
}
|
||||
|
||||
fn test<A: Foo>(arg: EFoo) {
|
||||
match arg {
|
||||
A::X => { // error!
|
||||
println!("A::X");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`const` and `static` mean different things. A `const` is a compile-time
|
||||
constant, an alias for a literal value. This property means you can match it
|
||||
directly within a pattern.
|
||||
|
@ -247,6 +422,39 @@ match Some(42) {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0161: r##"
|
||||
A value was moved. However, its size was not known at compile time, and only
|
||||
values of a known size can be moved.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0161
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<[isize]> = box *array;
|
||||
// error: cannot move a value of type [isize]: the size of [isize] cannot
|
||||
// be statically determined
|
||||
}
|
||||
```
|
||||
|
||||
In Rust, you can only move a value when its size is known at compile time.
|
||||
|
||||
To work around this restriction, consider "hiding" the value behind a reference:
|
||||
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
|
||||
it around as usual. Example:
|
||||
|
||||
```
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<&[isize]> = box array; // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0162: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
|
@ -468,158 +676,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
|
|||
See also https://github.com/rust-lang/rust/issues/14587
|
||||
"##,
|
||||
|
||||
E0010: r##"
|
||||
The value of statics and constants must be known at compile time, and they live
|
||||
for the entire lifetime of a program. Creating a boxed value allocates memory on
|
||||
the heap at runtime, and therefore cannot be done at compile time. Erroneous
|
||||
code example:
|
||||
|
||||
```compile_fail,E0010
|
||||
#![feature(box_syntax)]
|
||||
|
||||
const CON : Box<i32> = box 0;
|
||||
```
|
||||
"##,
|
||||
|
||||
E0013: r##"
|
||||
Static and const variables can refer to other const variables. But a const
|
||||
variable cannot refer to a static variable. For example, `Y` cannot refer to
|
||||
`X` here:
|
||||
|
||||
```compile_fail,E0013
|
||||
static X: i32 = 42;
|
||||
const Y: i32 = X;
|
||||
```
|
||||
|
||||
To fix this, the value can be extracted as a const and then used:
|
||||
|
||||
```
|
||||
const A: i32 = 42;
|
||||
static X: i32 = A;
|
||||
const Y: i32 = A;
|
||||
```
|
||||
"##,
|
||||
|
||||
// FIXME(#57563) Change the language here when const fn stabilizes
|
||||
E0015: r##"
|
||||
The only functions that can be called in static or constant expressions are
|
||||
`const` functions, and struct/enum constructors. `const` functions are only
|
||||
available on a nightly compiler. Rust currently does not support more general
|
||||
compile-time function execution.
|
||||
|
||||
```
|
||||
const FOO: Option<u8> = Some(1); // enum constructor
|
||||
struct Bar {x: u8}
|
||||
const BAR: Bar = Bar {x: 1}; // struct constructor
|
||||
```
|
||||
|
||||
See [RFC 911] for more details on the design of `const fn`s.
|
||||
|
||||
[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
|
||||
"##,
|
||||
|
||||
E0017: r##"
|
||||
References in statics and constants may only refer to immutable values.
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0017
|
||||
static X: i32 = 1;
|
||||
const C: i32 = 2;
|
||||
|
||||
// these three are not allowed:
|
||||
const CR: &mut i32 = &mut C;
|
||||
static STATIC_REF: &'static mut i32 = &mut X;
|
||||
static CONST_REF: &'static mut i32 = &mut C;
|
||||
```
|
||||
|
||||
Statics are shared everywhere, and if they refer to mutable data one might
|
||||
violate memory safety since holding multiple mutable references to shared data
|
||||
is not allowed.
|
||||
|
||||
If you really want global mutable state, try using `static mut` or a global
|
||||
`UnsafeCell`.
|
||||
"##,
|
||||
|
||||
E0019: r##"
|
||||
A function call isn't allowed in the const's initialization expression
|
||||
because the expression's value must be known at compile-time. Erroneous code
|
||||
example:
|
||||
|
||||
```compile_fail
|
||||
enum Test {
|
||||
V1
|
||||
}
|
||||
|
||||
impl Test {
|
||||
fn test(&self) -> i32 {
|
||||
12
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const FOO: Test = Test::V1;
|
||||
|
||||
const A: i32 = FOO.test(); // You can't call Test::func() here!
|
||||
}
|
||||
```
|
||||
|
||||
Remember: you can't use a function call inside a const's initialization
|
||||
expression! However, you can totally use it anywhere else:
|
||||
|
||||
```
|
||||
enum Test {
|
||||
V1
|
||||
}
|
||||
|
||||
impl Test {
|
||||
fn func(&self) -> i32 {
|
||||
12
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const FOO: Test = Test::V1;
|
||||
|
||||
FOO.func(); // here is good
|
||||
let x = FOO.func(); // or even here!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0133: r##"
|
||||
Unsafe code was used outside of an unsafe function or block.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0133
|
||||
unsafe fn f() { return; } // This is the unsafe code
|
||||
|
||||
fn main() {
|
||||
f(); // error: call to unsafe function requires unsafe function or block
|
||||
}
|
||||
```
|
||||
|
||||
Using unsafe functionality is potentially dangerous and disallowed by safety
|
||||
checks. Examples:
|
||||
|
||||
* Dereferencing raw pointers
|
||||
* Calling functions via FFI
|
||||
* Calling functions marked unsafe
|
||||
|
||||
These safety checks can be relaxed for a section of the code by wrapping the
|
||||
unsafe instructions with an `unsafe` block. For instance:
|
||||
|
||||
```
|
||||
unsafe fn f() { return; }
|
||||
|
||||
fn main() {
|
||||
unsafe { f(); } // ok!
|
||||
}
|
||||
```
|
||||
|
||||
See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
"##,
|
||||
|
||||
E0373: r##"
|
||||
This error occurs when an attempt is made to use data captured by a closure,
|
||||
when that data may no longer exist. It's most commonly seen when attempting to
|
||||
|
@ -672,7 +728,9 @@ about safety.
|
|||
"##,
|
||||
|
||||
E0381: r##"
|
||||
It is not allowed to use or capture an uninitialized variable. For example:
|
||||
It is not allowed to use or capture an uninitialized variable.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0381
|
||||
fn main() {
|
||||
|
@ -694,7 +752,9 @@ fn main() {
|
|||
|
||||
E0382: r##"
|
||||
This error occurs when an attempt is made to use a variable after its contents
|
||||
have been moved elsewhere. For example:
|
||||
have been moved elsewhere.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0382
|
||||
struct MyStruct { s: u32 }
|
||||
|
@ -842,7 +902,8 @@ x = Foo { a: 2 };
|
|||
|
||||
E0384: r##"
|
||||
This error occurs when an attempt is made to reassign an immutable variable.
|
||||
For example:
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0384
|
||||
fn main() {
|
||||
|
@ -862,13 +923,15 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
/*E0386: r##"
|
||||
E0386: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
This error occurs when an attempt is made to mutate the target of a mutable
|
||||
reference stored inside an immutable container.
|
||||
|
||||
For example, this can happen when storing a `&mut` inside an immutable `Box`:
|
||||
|
||||
```compile_fail,E0386
|
||||
```
|
||||
let mut x: i64 = 1;
|
||||
let y: Box<_> = Box::new(&mut x);
|
||||
**y = 2; // error, cannot assign to data in an immutable container
|
||||
|
@ -892,13 +955,15 @@ let x: i64 = 1;
|
|||
let y: Box<Cell<_>> = Box::new(Cell::new(x));
|
||||
y.set(2);
|
||||
```
|
||||
"##,*/
|
||||
"##,
|
||||
|
||||
E0387: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
This error occurs when an attempt is made to mutate or mutably reference data
|
||||
that a closure has captured immutably. Examples of this error are shown below:
|
||||
that a closure has captured immutably.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
// Accepts a function or a closure that captures its environment immutably.
|
||||
|
@ -963,7 +1028,7 @@ An attempt was made to mutate data using a non-mutable reference. This
|
|||
commonly occurs when attempting to assign to a non-mutable reference of a
|
||||
mutable reference (`&(&mut T)`).
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
struct FancyNum {
|
||||
|
@ -1022,43 +1087,11 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0161: r##"
|
||||
A value was moved. However, its size was not known at compile time, and only
|
||||
values of a known size can be moved.
|
||||
E0492: r##"
|
||||
A borrow of a constant containing interior mutability was attempted.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<[isize]> = box *array;
|
||||
// error: cannot move a value of type [isize]: the size of [isize] cannot
|
||||
// be statically determined
|
||||
}
|
||||
```
|
||||
|
||||
In Rust, you can only move a value when its size is known at compile time.
|
||||
|
||||
To work around this restriction, consider "hiding" the value behind a reference:
|
||||
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
|
||||
it around as usual. Example:
|
||||
|
||||
```
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<&[isize]> = box array; // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0492: r##"
|
||||
A borrow of a constant containing interior mutability was attempted. Erroneous
|
||||
code example:
|
||||
|
||||
```compile_fail,E0492
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
|
@ -1174,7 +1207,9 @@ static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields
|
|||
"##,
|
||||
|
||||
E0499: r##"
|
||||
A variable was borrowed as mutable more than once. Erroneous code example:
|
||||
A variable was borrowed as mutable more than once.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0499
|
||||
let mut i = 0;
|
||||
|
@ -1205,7 +1240,9 @@ a;
|
|||
"##,
|
||||
|
||||
E0500: r##"
|
||||
A borrowed variable was used by a closure. Example of erroneous code:
|
||||
A borrowed variable was used by a closure.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0500
|
||||
fn you_know_nothing(jon_snow: &mut i32) {
|
||||
|
@ -1256,7 +1293,7 @@ situation, the closure is borrowing the variable. Take a look at
|
|||
http://rustbyexample.com/fn/closures/capture.html for more information about
|
||||
capturing.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0501
|
||||
fn inside_closure(x: &mut i32) {
|
||||
|
@ -1329,7 +1366,7 @@ E0502: r##"
|
|||
This error indicates that you are trying to borrow a variable as mutable when it
|
||||
has already been borrowed as immutable.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0502
|
||||
fn bar(x: &mut i32) {}
|
||||
|
@ -1360,7 +1397,7 @@ https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html.
|
|||
E0503: r##"
|
||||
A value was used after it was mutably borrowed.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0503
|
||||
fn main() {
|
||||
|
@ -1418,7 +1455,7 @@ E0504: r##"
|
|||
This error occurs when an attempt is made to move a borrowed variable into a
|
||||
closure.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
struct FancyNum {
|
||||
|
@ -1609,7 +1646,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
|
|||
E0506: r##"
|
||||
This error occurs when an attempt is made to assign to a borrowed value.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0506
|
||||
struct FancyNum {
|
||||
|
@ -1827,7 +1864,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
|
|||
E0508: r##"
|
||||
A value was moved out of a non-copy fixed-size array.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0508
|
||||
struct NonCopy;
|
||||
|
@ -1872,7 +1909,7 @@ E0509: r##"
|
|||
This error occurs when an attempt is made to move out of a value whose type
|
||||
implements the `Drop` trait.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0509
|
||||
struct FancyNum {
|
||||
|
@ -1982,30 +2019,14 @@ Here executing `x = None` would modify the value being matched and require us
|
|||
to go "back in time" to the `None` arm.
|
||||
"##,
|
||||
|
||||
E0579: r##"
|
||||
When matching against an exclusive range, the compiler verifies that the range
|
||||
is non-empty. Exclusive range patterns include the start point but not the end
|
||||
point, so this is equivalent to requiring the start of the range to be less
|
||||
than the end of the range.
|
||||
|
||||
For example:
|
||||
|
||||
```compile_fail
|
||||
match 5u32 {
|
||||
// This range is ok, albeit pointless.
|
||||
1 .. 2 => {}
|
||||
// This range is empty, and the compiler can tell.
|
||||
5 .. 5 => {}
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0515: r##"
|
||||
Cannot return value that references local variable
|
||||
|
||||
Local variables, function parameters and temporaries are all dropped before the
|
||||
end of the function body. So a reference to them cannot be returned.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0515
|
||||
fn get_dangling_reference() -> &'static i32 {
|
||||
let x = 0;
|
||||
|
@ -2101,6 +2122,28 @@ fn dragoooon(x: &mut isize) {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0579: r##"
|
||||
When matching against an exclusive range, the compiler verifies that the range
|
||||
is non-empty. Exclusive range patterns include the start point but not the end
|
||||
point, so this is equivalent to requiring the start of the range to be less
|
||||
than the end of the range.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0579
|
||||
#![feature(exclusive_range_pattern)]
|
||||
|
||||
fn main() {
|
||||
match 5u32 {
|
||||
// This range is ok, albeit pointless.
|
||||
1 .. 2 => {}
|
||||
// This range is empty, and the compiler can tell.
|
||||
5 .. 5 => {} // error!
|
||||
}
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0595: r##"
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
|
@ -2124,7 +2167,7 @@ let mut c = || { x += 1 };
|
|||
E0596: r##"
|
||||
This error occurs because you tried to mutably borrow a non-mutable variable.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0596
|
||||
let x = 1;
|
||||
|
@ -2143,7 +2186,7 @@ let y = &mut x; // ok!
|
|||
E0597: r##"
|
||||
This error occurs because a value was dropped while it was still borrowed
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0597
|
||||
struct Foo<'a> {
|
||||
|
@ -2180,6 +2223,8 @@ E0626: r##"
|
|||
This error occurs because a borrow in a generator persists across a
|
||||
yield point.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0626
|
||||
# #![feature(generators, generator_trait, pin)]
|
||||
# use std::ops::Generator;
|
||||
|
@ -2271,7 +2316,7 @@ E0712: r##"
|
|||
This error occurs because a borrow of a thread-local variable was made inside a
|
||||
function which outlived the lifetime of the function.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0712
|
||||
#![feature(thread_local)]
|
||||
|
@ -2293,7 +2338,7 @@ E0713: r##"
|
|||
This error occurs when an attempt is made to borrow state past the end of the
|
||||
lifetime of a type that implements the `Drop` trait.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0713
|
||||
#![feature(nll)]
|
||||
|
|
|
@ -94,7 +94,8 @@ impl<'a> Resolver<'a> {
|
|||
where T: ToNameBinding<'a>,
|
||||
{
|
||||
let binding = def.to_name_binding(self.arenas);
|
||||
if let Err(old_binding) = self.try_define(parent, ident, ns, binding) {
|
||||
let key = self.new_key(ident, ns);
|
||||
if let Err(old_binding) = self.try_define(parent, key, binding) {
|
||||
self.report_conflict(parent, ident, ns, old_binding, &binding);
|
||||
}
|
||||
}
|
||||
|
@ -349,9 +350,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
|
||||
self.r.indeterminate_imports.push(directive);
|
||||
match directive.subclass {
|
||||
// Don't add unresolved underscore imports to modules
|
||||
SingleImport { target: Ident { name: kw::Underscore, .. }, .. } => {}
|
||||
SingleImport { target, type_ns_only, .. } => {
|
||||
self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
|
||||
let key = this.new_key(target, ns);
|
||||
let mut resolution = this.resolution(current_module, key).borrow_mut();
|
||||
resolution.add_single_import(directive);
|
||||
});
|
||||
}
|
||||
|
@ -407,7 +411,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
};
|
||||
match use_tree.kind {
|
||||
ast::UseTreeKind::Simple(rename, ..) => {
|
||||
let mut ident = use_tree.ident().gensym_if_underscore();
|
||||
let mut ident = use_tree.ident();
|
||||
let mut module_path = prefix;
|
||||
let mut source = module_path.pop().unwrap();
|
||||
let mut type_ns_only = false;
|
||||
|
@ -585,7 +589,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
let parent_scope = &self.parent_scope;
|
||||
let parent = parent_scope.module;
|
||||
let expansion = parent_scope.expansion;
|
||||
let ident = item.ident.gensym_if_underscore();
|
||||
let ident = item.ident;
|
||||
let sp = item.span;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
|
||||
|
@ -851,10 +855,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
|
||||
let parent = self.parent_scope.module;
|
||||
let Export { ident, res, vis, span } = child;
|
||||
// FIXME: We shouldn't create the gensym here, it should come from metadata,
|
||||
// but metadata cannot encode gensyms currently, so we create it here.
|
||||
// This is only a guess, two equivalent idents may incorrectly get different gensyms here.
|
||||
let ident = ident.gensym_if_underscore();
|
||||
let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
|
||||
// Record primary definitions.
|
||||
match res {
|
||||
|
|
|
@ -80,11 +80,11 @@ impl<'a> Resolver<'a> {
|
|||
names: &mut Vec<TypoSuggestion>,
|
||||
filter_fn: &impl Fn(Res) -> bool,
|
||||
) {
|
||||
for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() {
|
||||
for (key, resolution) in self.resolutions(module).borrow().iter() {
|
||||
if let Some(binding) = resolution.borrow().binding {
|
||||
let res = binding.res();
|
||||
if filter_fn(res) {
|
||||
names.push(TypoSuggestion::from_res(ident.name, res));
|
||||
names.push(TypoSuggestion::from_res(key.ident.name, res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -849,7 +849,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
}
|
||||
|
||||
let resolutions = self.r.resolutions(crate_module).borrow();
|
||||
let resolution = resolutions.get(&(ident, MacroNS))?;
|
||||
let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?;
|
||||
let binding = resolution.borrow().binding()?;
|
||||
if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
|
||||
let module_name = crate_module.kind.name().unwrap();
|
||||
|
|
|
@ -1611,6 +1611,56 @@ fn print_on_failure(state: &State) {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0574: r##"
|
||||
Something other than a struct, variant or union has been used when one was
|
||||
expected.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0574
|
||||
mod Mordor {}
|
||||
|
||||
let sauron = Mordor { x: () }; // error!
|
||||
|
||||
enum Jak {
|
||||
Daxter { i: isize },
|
||||
}
|
||||
|
||||
let eco = Jak::Daxter { i: 1 };
|
||||
match eco {
|
||||
Jak { i } => {} // error!
|
||||
}
|
||||
```
|
||||
|
||||
In all these errors, a type was expected. For example, in the first error,
|
||||
we tried to instantiate the `Mordor` module, which is impossible. If you want
|
||||
to instantiate a type inside a module, you can do it as follow:
|
||||
|
||||
```
|
||||
mod Mordor {
|
||||
pub struct TheRing {
|
||||
pub x: usize,
|
||||
}
|
||||
}
|
||||
|
||||
let sauron = Mordor::TheRing { x: 1 }; // ok!
|
||||
```
|
||||
|
||||
In the second error, we tried to bind the `Jak` enum directly, which is not
|
||||
possible: you can only bind one of its variants. To do so:
|
||||
|
||||
```
|
||||
enum Jak {
|
||||
Daxter { i: isize },
|
||||
}
|
||||
|
||||
let eco = Jak::Daxter { i: 1 };
|
||||
match eco {
|
||||
Jak::Daxter { i } => {} // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0603: r##"
|
||||
A private item was used outside its scope.
|
||||
|
||||
|
@ -1739,7 +1789,6 @@ struct Foo<X = Box<Self>> {
|
|||
// E0467, removed
|
||||
// E0470, removed
|
||||
E0573,
|
||||
E0574,
|
||||
E0575,
|
||||
E0576,
|
||||
E0577,
|
||||
|
|
|
@ -432,7 +432,22 @@ impl ModuleKind {
|
|||
}
|
||||
}
|
||||
|
||||
type Resolutions<'a> = RefCell<FxIndexMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
|
||||
/// A key that identifies a binding in a given `Module`.
|
||||
///
|
||||
/// Multiple bindings in the same module can have the same key (in a valid
|
||||
/// program) if all but one of them come from glob imports.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct BindingKey {
|
||||
/// The identifier for the binding, aways the `modern` version of the
|
||||
/// identifier.
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
/// 0 if ident is not `_`, otherwise a value that's unique to the specific
|
||||
/// `_` in the expanded AST that introduced this binding.
|
||||
disambiguator: u32,
|
||||
}
|
||||
|
||||
type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>;
|
||||
|
||||
/// One node in the tree of modules.
|
||||
pub struct ModuleData<'a> {
|
||||
|
@ -492,8 +507,8 @@ impl<'a> ModuleData<'a> {
|
|||
fn for_each_child<R, F>(&'a self, resolver: &mut R, mut f: F)
|
||||
where R: AsMut<Resolver<'a>>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>)
|
||||
{
|
||||
for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
|
||||
name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
|
||||
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
|
||||
name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -882,6 +897,7 @@ pub struct Resolver<'a> {
|
|||
module_map: FxHashMap<DefId, Module<'a>>,
|
||||
extern_module_map: FxHashMap<DefId, Module<'a>>,
|
||||
binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
|
||||
underscore_disambiguator: u32,
|
||||
|
||||
/// Maps glob imports to the names of items actually imported.
|
||||
pub glob_map: GlobMap,
|
||||
|
@ -1160,6 +1176,7 @@ impl<'a> Resolver<'a> {
|
|||
extern_crate_map: Default::default(),
|
||||
export_map: FxHashMap::default(),
|
||||
trait_map: Default::default(),
|
||||
underscore_disambiguator: 0,
|
||||
empty_module,
|
||||
module_map,
|
||||
block_map: Default::default(),
|
||||
|
@ -1284,6 +1301,17 @@ impl<'a> Resolver<'a> {
|
|||
self.arenas.alloc_module(module)
|
||||
}
|
||||
|
||||
fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
|
||||
let ident = ident.modern();
|
||||
let disambiguator = if ident.name == kw::Underscore {
|
||||
self.underscore_disambiguator += 1;
|
||||
self.underscore_disambiguator
|
||||
} else {
|
||||
0
|
||||
};
|
||||
BindingKey { ident, ns, disambiguator }
|
||||
}
|
||||
|
||||
fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> {
|
||||
if module.populate_on_access.get() {
|
||||
module.populate_on_access.set(false);
|
||||
|
@ -1292,9 +1320,9 @@ impl<'a> Resolver<'a> {
|
|||
&module.lazy_resolutions
|
||||
}
|
||||
|
||||
fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
fn resolution(&mut self, module: Module<'a>, key: BindingKey)
|
||||
-> &'a RefCell<NameResolution<'a>> {
|
||||
*self.resolutions(module).borrow_mut().entry((ident.modern(), ns))
|
||||
*self.resolutions(module).borrow_mut().entry(key)
|
||||
.or_insert_with(|| self.arenas.alloc_name_resolution())
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope
|
|||
use crate::Determinacy::{self, *};
|
||||
use crate::Namespace::{self, TypeNS, MacroNS};
|
||||
use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
|
||||
use crate::{Resolver, ResolutionError, Segment, ModuleKind};
|
||||
use crate::{Resolver, ResolutionError, BindingKey, Segment, ModuleKind};
|
||||
use crate::{names_to_string, module_to_string};
|
||||
use crate::diagnostics::Suggestion;
|
||||
|
||||
|
@ -235,7 +235,8 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let resolution = self.resolution(module, ident, ns)
|
||||
let key = self.new_key(ident, ns);
|
||||
let resolution = self.resolution(module, key)
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
|
||||
|
||||
|
@ -447,17 +448,16 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
|
||||
// Define the name or return the existing binding if there is a collision.
|
||||
pub fn try_define(
|
||||
crate fn try_define(
|
||||
&mut self,
|
||||
module: Module<'a>,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
key: BindingKey,
|
||||
binding: &'a NameBinding<'a>,
|
||||
) -> Result<(), &'a NameBinding<'a>> {
|
||||
let res = binding.res();
|
||||
self.check_reserved_macro_name(ident, res);
|
||||
self.check_reserved_macro_name(key.ident, res);
|
||||
self.set_binding_parent_module(binding, module);
|
||||
self.update_resolution(module, ident, ns, |this, resolution| {
|
||||
self.update_resolution(module, key, |this, resolution| {
|
||||
if let Some(old_binding) = resolution.binding {
|
||||
if res == Res::Err {
|
||||
// Do not override real bindings with `Res::Err`s from error recovery.
|
||||
|
@ -479,8 +479,9 @@ impl<'a> Resolver<'a> {
|
|||
} else {
|
||||
(binding, old_binding)
|
||||
};
|
||||
if glob_binding.res() != nonglob_binding.res() &&
|
||||
ns == MacroNS && nonglob_binding.expansion != ExpnId::root() {
|
||||
if glob_binding.res() != nonglob_binding.res()
|
||||
&& key.ns == MacroNS && nonglob_binding.expansion != ExpnId::root()
|
||||
{
|
||||
resolution.binding = Some(this.ambiguity(
|
||||
AmbiguityKind::GlobVsExpanded,
|
||||
nonglob_binding,
|
||||
|
@ -499,9 +500,9 @@ impl<'a> Resolver<'a> {
|
|||
DUPLICATE_MACRO_EXPORTS,
|
||||
CRATE_NODE_ID,
|
||||
binding.span,
|
||||
&format!("a macro named `{}` has already been exported", ident),
|
||||
&format!("a macro named `{}` has already been exported", key.ident),
|
||||
BuiltinLintDiagnostics::DuplicatedMacroExports(
|
||||
ident, old_binding.span, binding.span));
|
||||
key.ident, old_binding.span, binding.span));
|
||||
|
||||
resolution.binding = Some(binding);
|
||||
} else {
|
||||
|
@ -531,9 +532,9 @@ impl<'a> Resolver<'a> {
|
|||
// Use `f` to mutate the resolution of the name in the module.
|
||||
// If the resolution becomes a success, define it in the module's glob importers.
|
||||
fn update_resolution<T, F>(
|
||||
&mut self, module: Module<'a>,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
&mut self,
|
||||
module: Module<'a>,
|
||||
key: BindingKey,
|
||||
f: F,
|
||||
) -> T
|
||||
where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
|
||||
|
@ -541,7 +542,7 @@ impl<'a> Resolver<'a> {
|
|||
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
|
||||
// during which the resolution might end up getting re-defined via a glob cycle.
|
||||
let (binding, t) = {
|
||||
let resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
|
||||
let resolution = &mut *self.resolution(module, key).borrow_mut();
|
||||
let old_binding = resolution.binding();
|
||||
|
||||
let t = f(self, resolution);
|
||||
|
@ -558,7 +559,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
// Define `binding` in `module`s glob importers.
|
||||
for directive in module.glob_importers.borrow_mut().iter() {
|
||||
let mut ident = ident.modern();
|
||||
let mut ident = key.ident;
|
||||
let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
|
||||
Some(Some(def)) => self.macro_def_scope(def),
|
||||
Some(None) => directive.parent_scope.module,
|
||||
|
@ -566,7 +567,8 @@ impl<'a> Resolver<'a> {
|
|||
};
|
||||
if self.is_accessible_from(binding.vis, scope) {
|
||||
let imported_binding = self.import(binding, directive);
|
||||
let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
|
||||
let key = BindingKey { ident, ..key };
|
||||
let _ = self.try_define(directive.parent_scope.module, key, imported_binding);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,7 +582,8 @@ impl<'a> Resolver<'a> {
|
|||
let dummy_binding = self.dummy_binding;
|
||||
let dummy_binding = self.import(dummy_binding, directive);
|
||||
self.per_ns(|this, ns| {
|
||||
let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding);
|
||||
let key = this.new_key(target, ns);
|
||||
let _ = this.try_define(directive.parent_scope.module, key, dummy_binding);
|
||||
// Consider erroneous imports used to avoid duplicate diagnostics.
|
||||
this.record_use(target, ns, dummy_binding, false);
|
||||
});
|
||||
|
@ -820,8 +823,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let parent = directive.parent_scope.module;
|
||||
match source_bindings[ns].get() {
|
||||
Err(Undetermined) => indeterminate = true,
|
||||
// Don't update the resolution, because it was never added.
|
||||
Err(Determined) if target.name == kw::Underscore => {}
|
||||
Err(Determined) => {
|
||||
this.update_resolution(parent, target, ns, |_, resolution| {
|
||||
let key = this.new_key(target, ns);
|
||||
this.update_resolution(parent, key, |_, resolution| {
|
||||
resolution.single_imports.remove(&PtrKey(directive));
|
||||
});
|
||||
}
|
||||
|
@ -1052,7 +1058,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
_ => None,
|
||||
};
|
||||
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
|
||||
let names = resolutions.filter_map(|(&(ref i, _), resolution)| {
|
||||
let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
|
||||
if *i == ident { return None; } // Never suggest the same name
|
||||
match *resolution.borrow() {
|
||||
NameResolution { binding: Some(name_binding), .. } => {
|
||||
|
@ -1301,19 +1307,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
// Ensure that `resolutions` isn't borrowed during `try_define`,
|
||||
// since it might get updated via a glob cycle.
|
||||
let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(ident, resolution)| {
|
||||
resolution.borrow().binding().map(|binding| (*ident, binding))
|
||||
let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(key, resolution)| {
|
||||
resolution.borrow().binding().map(|binding| (*key, binding))
|
||||
}).collect::<Vec<_>>();
|
||||
for ((mut ident, ns), binding) in bindings {
|
||||
let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
|
||||
for (mut key, binding) in bindings {
|
||||
let scope = match key.ident.span.reverse_glob_adjust(module.expansion, directive.span) {
|
||||
Some(Some(def)) => self.r.macro_def_scope(def),
|
||||
Some(None) => directive.parent_scope.module,
|
||||
None => continue,
|
||||
};
|
||||
if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
|
||||
let imported_binding = self.r.import(binding, directive);
|
||||
let _ =
|
||||
self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding);
|
||||
let _ = self.r.try_define(directive.parent_scope.module, key, imported_binding);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1329,29 +1334,23 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
let mut reexports = Vec::new();
|
||||
|
||||
for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() {
|
||||
let resolution = &mut *resolution.borrow_mut();
|
||||
let binding = match resolution.binding {
|
||||
Some(binding) => binding,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
module.for_each_child(self.r, |this, ident, ns, binding| {
|
||||
// Filter away ambiguous imports and anything that has def-site
|
||||
// hygiene.
|
||||
// FIXME: Implement actual cross-crate hygiene.
|
||||
let is_good_import = binding.is_import() && !binding.is_ambiguity()
|
||||
&& !ident.span.modern().from_expansion();
|
||||
&& !ident.span.from_expansion();
|
||||
if is_good_import || binding.is_macro_def() {
|
||||
let res = binding.res();
|
||||
if res != Res::Err {
|
||||
if let Some(def_id) = res.opt_def_id() {
|
||||
if !def_id.is_local() {
|
||||
self.r.cstore.export_macros_untracked(def_id.krate);
|
||||
this.cstore.export_macros_untracked(def_id.krate);
|
||||
}
|
||||
}
|
||||
reexports.push(Export {
|
||||
ident: ident.modern(),
|
||||
res: res,
|
||||
ident,
|
||||
res,
|
||||
span: binding.span,
|
||||
vis: binding.vis,
|
||||
});
|
||||
|
@ -1360,7 +1359,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
|
||||
if ns == TypeNS && orig_binding.is_variant() &&
|
||||
!orig_binding.vis.is_at_least(binding.vis, &*self) {
|
||||
!orig_binding.vis.is_at_least(binding.vis, &*this) {
|
||||
let msg = match directive.subclass {
|
||||
ImportDirectiveSubclass::SingleImport { .. } => {
|
||||
format!("variant `{}` is private and cannot be re-exported",
|
||||
|
@ -1372,33 +1371,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
|
||||
Some(binding.span),
|
||||
msg.clone());
|
||||
let fresh = self.r.session.one_time_diagnostics
|
||||
let fresh = this.session.one_time_diagnostics
|
||||
.borrow_mut().insert(error_id);
|
||||
if !fresh {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
msg
|
||||
},
|
||||
ref s @ _ => bug!("unexpected import subclass {:?}", s)
|
||||
};
|
||||
let mut err = self.r.session.struct_span_err(binding.span, &msg);
|
||||
let mut err = this.session.struct_span_err(binding.span, &msg);
|
||||
|
||||
let imported_module = match directive.imported_module.get() {
|
||||
Some(ModuleOrUniformRoot::Module(module)) => module,
|
||||
_ => bug!("module should exist"),
|
||||
};
|
||||
let parent_module = imported_module.parent.expect("parent should exist");
|
||||
let resolutions = self.r.resolutions(parent_module).borrow();
|
||||
let resolutions = this.resolutions(parent_module).borrow();
|
||||
let enum_path_segment_index = directive.module_path.len() - 1;
|
||||
let enum_ident = directive.module_path[enum_path_segment_index].ident;
|
||||
|
||||
let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
|
||||
let key = this.new_key(enum_ident, TypeNS);
|
||||
let enum_resolution = resolutions.get(&key)
|
||||
.expect("resolution should exist");
|
||||
let enum_span = enum_resolution.borrow()
|
||||
.binding.expect("binding should exist")
|
||||
.span;
|
||||
let enum_def_span = self.r.session.source_map().def_span(enum_span);
|
||||
let enum_def_snippet = self.r.session.source_map()
|
||||
let enum_def_span = this.session.source_map().def_span(enum_span);
|
||||
let enum_def_snippet = this.session.source_map()
|
||||
.span_to_snippet(enum_def_span).expect("snippet should exist");
|
||||
// potentially need to strip extant `crate`/`pub(path)` for suggestion
|
||||
let after_vis_index = enum_def_snippet.find("enum")
|
||||
|
@ -1406,7 +1406,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let suggestion = format!("pub {}",
|
||||
&enum_def_snippet[after_vis_index..]);
|
||||
|
||||
self.r.session
|
||||
this.session
|
||||
.diag_span_suggestion_once(&mut err,
|
||||
DiagnosticMessageId::ErrorId(0),
|
||||
enum_def_span,
|
||||
|
@ -1415,7 +1415,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if reexports.len() > 0 {
|
||||
if let Some(def_id) = module.def_id() {
|
||||
|
|
|
@ -115,15 +115,17 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
F: FnOnce(&mut Self),
|
||||
{
|
||||
let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id);
|
||||
if self.tcx.has_typeck_tables(item_def_id) {
|
||||
let tables = self.tcx.typeck_tables_of(item_def_id);
|
||||
let old_tables = self.save_ctxt.tables;
|
||||
self.save_ctxt.tables = tables;
|
||||
f(self);
|
||||
self.save_ctxt.tables = old_tables;
|
||||
|
||||
let tables = if self.tcx.has_typeck_tables(item_def_id) {
|
||||
self.tcx.typeck_tables_of(item_def_id)
|
||||
} else {
|
||||
f(self);
|
||||
}
|
||||
self.save_ctxt.empty_tables
|
||||
};
|
||||
|
||||
let old_tables = self.save_ctxt.tables;
|
||||
self.save_ctxt.tables = tables;
|
||||
f(self);
|
||||
self.save_ctxt.tables = old_tables;
|
||||
}
|
||||
|
||||
fn span_from_span(&self, span: Span) -> SpanData {
|
||||
|
@ -530,12 +532,14 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
for field in def.fields() {
|
||||
self.process_struct_field_def(field, item.id);
|
||||
self.visit_ty(&field.ty);
|
||||
}
|
||||
self.nest_tables(item.id, |v| {
|
||||
for field in def.fields() {
|
||||
v.process_struct_field_def(field, item.id);
|
||||
v.visit_ty(&field.ty);
|
||||
}
|
||||
|
||||
self.process_generic_params(ty_params, &qualname, item.id);
|
||||
v.process_generic_params(ty_params, &qualname, item.id);
|
||||
});
|
||||
}
|
||||
|
||||
fn process_enum(
|
||||
|
|
|
@ -48,6 +48,9 @@ use log::{debug, error, info};
|
|||
pub struct SaveContext<'l, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
tables: &'l ty::TypeckTables<'tcx>,
|
||||
/// Used as a fallback when nesting the typeck tables during item processing
|
||||
/// (if these are not available for that item, e.g. don't own a body)
|
||||
empty_tables: &'l ty::TypeckTables<'tcx>,
|
||||
access_levels: &'l AccessLevels,
|
||||
span_utils: SpanUtils<'tcx>,
|
||||
config: Config,
|
||||
|
@ -1114,6 +1117,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
|
|||
let save_ctxt = SaveContext {
|
||||
tcx,
|
||||
tables: &ty::TypeckTables::empty(None),
|
||||
empty_tables: &ty::TypeckTables::empty(None),
|
||||
access_levels: &access_levels,
|
||||
span_utils: SpanUtils::new(&tcx.sess),
|
||||
config: find_config(config),
|
||||
|
|
|
@ -611,6 +611,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
|
||||
debug!("supplied_sig_of_closure: closure is async fn body");
|
||||
self.deduce_future_output_from_obligations(expr_def_id)
|
||||
.unwrap_or_else(|| {
|
||||
// AFAIK, deducing the future output
|
||||
// always succeeds *except* in error cases
|
||||
// like #65159. I'd like to return Error
|
||||
// here, but I can't because I can't
|
||||
// easily (and locally) prove that we
|
||||
// *have* reported an
|
||||
// error. --nikomatsakis
|
||||
astconv.ty_infer(None, decl.output.span())
|
||||
})
|
||||
}
|
||||
|
||||
_ => astconv.ty_infer(None, decl.output.span()),
|
||||
|
@ -645,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn deduce_future_output_from_obligations(
|
||||
&self,
|
||||
expr_def_id: DefId,
|
||||
) -> Ty<'tcx> {
|
||||
) -> Option<Ty<'tcx>> {
|
||||
debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
|
||||
|
||||
let ret_coercion =
|
||||
|
@ -688,8 +698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
|
||||
output_ty
|
||||
|
|
|
@ -777,7 +777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
"items from traits can only be used if the trait is implemented and in scope"
|
||||
});
|
||||
let mut msg = format!(
|
||||
let message = |action| format!(
|
||||
"the following {traits_define} an item `{name}`, perhaps you need to {action} \
|
||||
{one_of_them}:",
|
||||
traits_define = if candidates.len() == 1 {
|
||||
|
@ -785,11 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
"traits define"
|
||||
},
|
||||
action = if let Some(param) = param_type {
|
||||
format!("restrict type parameter `{}` with", param)
|
||||
} else {
|
||||
"implement".to_string()
|
||||
},
|
||||
action = action,
|
||||
one_of_them = if candidates.len() == 1 {
|
||||
"it"
|
||||
} else {
|
||||
|
@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Get the `hir::Param` to verify whether it already has any bounds.
|
||||
// We do this to avoid suggesting code that ends up as `T: FooBar`,
|
||||
// instead we suggest `T: Foo + Bar` in that case.
|
||||
let mut has_bounds = None;
|
||||
let mut impl_trait = false;
|
||||
if let Node::GenericParam(ref param) = hir.get(id) {
|
||||
let kind = ¶m.kind;
|
||||
if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = kind {
|
||||
// We've found `fn foo(x: impl Trait)` instead of
|
||||
// `fn foo<T>(x: T)`. We want to suggest the correct
|
||||
// `fn foo(x: impl Trait + TraitBound)` instead of
|
||||
// `fn foo<T: TraitBound>(x: T)`. (See #63706.)
|
||||
impl_trait = true;
|
||||
has_bounds = param.bounds.get(1);
|
||||
} else {
|
||||
has_bounds = param.bounds.get(0);
|
||||
match hir.get(id) {
|
||||
Node::GenericParam(ref param) => {
|
||||
let mut impl_trait = false;
|
||||
let has_bounds = if let hir::GenericParamKind::Type {
|
||||
synthetic: Some(_), ..
|
||||
} = ¶m.kind {
|
||||
// We've found `fn foo(x: impl Trait)` instead of
|
||||
// `fn foo<T>(x: T)`. We want to suggest the correct
|
||||
// `fn foo(x: impl Trait + TraitBound)` instead of
|
||||
// `fn foo<T: TraitBound>(x: T)`. (#63706)
|
||||
impl_trait = true;
|
||||
param.bounds.get(1)
|
||||
} else {
|
||||
param.bounds.get(0)
|
||||
};
|
||||
let sp = hir.span(id);
|
||||
let sp = if let Some(first_bound) = has_bounds {
|
||||
// `sp` only covers `T`, change it so that it covers
|
||||
// `T:` when appropriate
|
||||
sp.until(first_bound.span())
|
||||
} else {
|
||||
sp
|
||||
};
|
||||
// FIXME: contrast `t.def_id` against `param.bounds` to not suggest
|
||||
// traits already there. That can happen when the cause is that
|
||||
// we're in a const scope or associated function used as a method.
|
||||
err.span_suggestions(
|
||||
sp,
|
||||
&message(format!(
|
||||
"restrict type parameter `{}` with",
|
||||
param.name.ident().as_str(),
|
||||
)),
|
||||
candidates.iter().map(|t| format!(
|
||||
"{}{} {}{}",
|
||||
param.name.ident().as_str(),
|
||||
if impl_trait { " +" } else { ":" },
|
||||
self.tcx.def_path_str(t.def_id),
|
||||
if has_bounds.is_some() { " + "} else { "" },
|
||||
)),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
suggested = true;
|
||||
}
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(.., bounds, _), ident, ..
|
||||
}) => {
|
||||
let (sp, sep, article) = if bounds.is_empty() {
|
||||
(ident.span.shrink_to_hi(), ":", "a")
|
||||
} else {
|
||||
(bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
|
||||
};
|
||||
err.span_suggestions(
|
||||
sp,
|
||||
&message(format!("add {} supertrait for", article)),
|
||||
candidates.iter().map(|t| format!(
|
||||
"{} {}",
|
||||
sep,
|
||||
self.tcx.def_path_str(t.def_id),
|
||||
)),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
suggested = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let sp = hir.span(id);
|
||||
// `sp` only covers `T`, change it so that it covers `T:` when appropriate.
|
||||
let sp = if let Some(first_bound) = has_bounds {
|
||||
sp.until(first_bound.span())
|
||||
} else {
|
||||
sp
|
||||
};
|
||||
|
||||
// FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
|
||||
// already there. That can happen when the cause is that we're in a const
|
||||
// scope or associated function used as a method.
|
||||
err.span_suggestions(
|
||||
sp,
|
||||
&msg[..],
|
||||
candidates.iter().map(|t| format!(
|
||||
"{}{} {}{}",
|
||||
param,
|
||||
if impl_trait { " +" } else { ":" },
|
||||
self.tcx.def_path_str(t.def_id),
|
||||
if has_bounds.is_some() { " + " } else { "" },
|
||||
)),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
suggested = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if !suggested {
|
||||
let mut msg = message(if let Some(param) = param_type {
|
||||
format!("restrict type parameter `{}` with", param)
|
||||
} else {
|
||||
"implement".to_string()
|
||||
});
|
||||
for (i, trait_info) in candidates.iter().enumerate() {
|
||||
msg.push_str(&format!(
|
||||
"\ncandidate #{}: `{}`",
|
||||
|
|
|
@ -334,8 +334,7 @@ impl Ident {
|
|||
if !Self::is_valid(&string) {
|
||||
panic!("`{:?}` is not a valid identifier", string)
|
||||
}
|
||||
// Get rid of gensyms to conservatively check rawness on the string contents only.
|
||||
if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() {
|
||||
if is_raw && !sym.can_be_raw() {
|
||||
panic!("`{}` cannot be a raw identifier", string);
|
||||
}
|
||||
Ident { sym, is_raw, span }
|
||||
|
|
|
@ -808,25 +808,13 @@ impl Ident {
|
|||
Ident::new(self.name, self.span.modern_and_legacy())
|
||||
}
|
||||
|
||||
/// Transforms an underscore identifier into one with the same name, but
|
||||
/// gensymed. Leaves non-underscore identifiers unchanged.
|
||||
pub fn gensym_if_underscore(self) -> Ident {
|
||||
if self.name == kw::Underscore {
|
||||
let name = with_interner(|interner| interner.gensymed(self.name));
|
||||
Ident::new(name, self.span)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the name to a `LocalInternedString`. This is a slowish
|
||||
/// operation because it requires locking the symbol interner.
|
||||
pub fn as_str(self) -> LocalInternedString {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
/// Convert the name to an `InternedString`. This is a slowish operation
|
||||
/// because it requires locking the symbol interner.
|
||||
/// Convert the name to an `InternedString`.
|
||||
pub fn as_interned_str(self) -> InternedString {
|
||||
self.name.as_interned_str()
|
||||
}
|
||||
|
@ -881,26 +869,9 @@ impl UseSpecializedDecodable for Ident {
|
|||
}
|
||||
}
|
||||
|
||||
/// A symbol is an interned or gensymed string. A gensym is a symbol that is
|
||||
/// never equal to any other symbol.
|
||||
/// An interned string.
|
||||
///
|
||||
/// Conceptually, a gensym can be thought of as a normal symbol with an
|
||||
/// invisible unique suffix. Gensyms are useful when creating new identifiers
|
||||
/// that must not match any existing identifiers, e.g. during macro expansion
|
||||
/// and syntax desugaring. Because gensyms should always be identifiers, all
|
||||
/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
|
||||
/// future the gensym-ness may be moved from `Symbol` to hygiene data.)
|
||||
///
|
||||
/// Examples:
|
||||
/// ```
|
||||
/// assert_eq!(Ident::from_str("_"), Ident::from_str("_"))
|
||||
/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_"))
|
||||
/// assert_ne!(
|
||||
/// Ident::from_str("_").gensym_if_underscore(),
|
||||
/// Ident::from_str("_").gensym_if_underscore(),
|
||||
/// )
|
||||
/// ```
|
||||
/// Internally, a symbol is implemented as an index, and all operations
|
||||
/// Internally, a `Symbol` is implemented as an index, and all operations
|
||||
/// (including hashing, equality, and ordering) operate on that index. The use
|
||||
/// of `rustc_index::newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
|
||||
/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes.
|
||||
|
@ -951,12 +922,9 @@ impl Symbol {
|
|||
})
|
||||
}
|
||||
|
||||
/// Convert to an `InternedString`. This is a slowish operation because it
|
||||
/// requires locking the symbol interner.
|
||||
/// Convert to an `InternedString`.
|
||||
pub fn as_interned_str(self) -> InternedString {
|
||||
with_interner(|interner| InternedString {
|
||||
symbol: interner.interned(self)
|
||||
})
|
||||
InternedString { symbol: self }
|
||||
}
|
||||
|
||||
pub fn as_u32(self) -> u32 {
|
||||
|
@ -966,12 +934,7 @@ impl Symbol {
|
|||
|
||||
impl fmt::Debug for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let is_gensymed = with_interner(|interner| interner.is_gensymed(*self));
|
||||
if is_gensymed {
|
||||
write!(f, "{}({:?})", self, self.0)
|
||||
} else {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,15 +957,11 @@ impl Decodable for Symbol {
|
|||
}
|
||||
|
||||
// The `&'static str`s in this type actually point into the arena.
|
||||
//
|
||||
// Note that normal symbols are indexed upward from 0, and gensyms are indexed
|
||||
// downward from SymbolIndex::MAX_AS_U32.
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
arena: DroplessArena,
|
||||
names: FxHashMap<&'static str, Symbol>,
|
||||
strings: Vec<&'static str>,
|
||||
gensyms: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl Interner {
|
||||
|
@ -1035,34 +994,10 @@ impl Interner {
|
|||
self.names.insert(string, name);
|
||||
name
|
||||
}
|
||||
|
||||
fn interned(&self, symbol: Symbol) -> Symbol {
|
||||
if (symbol.0.as_usize()) < self.strings.len() {
|
||||
symbol
|
||||
} else {
|
||||
self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]
|
||||
}
|
||||
}
|
||||
|
||||
fn gensymed(&mut self, symbol: Symbol) -> Symbol {
|
||||
self.gensyms.push(symbol);
|
||||
Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
|
||||
}
|
||||
|
||||
fn is_gensymed(&mut self, symbol: Symbol) -> bool {
|
||||
symbol.0.as_usize() >= self.strings.len()
|
||||
}
|
||||
|
||||
// Get the symbol as a string. `Symbol::as_str()` should be used in
|
||||
// preference to this function.
|
||||
pub fn get(&self, symbol: Symbol) -> &str {
|
||||
match self.strings.get(symbol.0.as_usize()) {
|
||||
Some(string) => string,
|
||||
None => {
|
||||
let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize];
|
||||
self.strings[symbol.0.as_usize()]
|
||||
}
|
||||
}
|
||||
self.strings[symbol.0.as_usize()]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1223,19 +1158,12 @@ impl fmt::Display for LocalInternedString {
|
|||
}
|
||||
}
|
||||
|
||||
/// An alternative to `Symbol` that is focused on string contents. It has two
|
||||
/// main differences to `Symbol`.
|
||||
/// An alternative to `Symbol` that is focused on string contents.
|
||||
///
|
||||
/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
|
||||
/// Its implementations of `Hash`, `PartialOrd` and `Ord` work with the
|
||||
/// string chars rather than the symbol integer. This is useful when hash
|
||||
/// stability is required across compile sessions, or a guaranteed sort
|
||||
/// ordering is required.
|
||||
///
|
||||
/// Second, gensym-ness is irrelevant. E.g.:
|
||||
/// ```
|
||||
/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
|
||||
/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct InternedString {
|
||||
symbol: Symbol,
|
||||
|
|
|
@ -14,13 +14,6 @@ fn interner_tests() {
|
|||
assert_eq!(i.intern("cat"), Symbol::new(1));
|
||||
// dog is still at zero
|
||||
assert_eq!(i.intern("dog"), Symbol::new(0));
|
||||
let z = i.intern("zebra");
|
||||
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32));
|
||||
// gensym of same string gets new number:
|
||||
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
|
||||
// gensym of *existing* string gets new number:
|
||||
let d = i.intern("dog");
|
||||
assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
10
src/test/ui/async-await/issues/issue-65159.rs
Normal file
10
src/test/ui/async-await/issues/issue-65159.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Regression test for #65159. We used to ICE.
|
||||
//
|
||||
// edition:2018
|
||||
|
||||
async fn copy() -> Result<()> //~ ERROR wrong number of type arguments
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() { }
|
9
src/test/ui/async-await/issues/issue-65159.stderr
Normal file
9
src/test/ui/async-await/issues/issue-65159.stderr
Normal file
|
@ -0,0 +1,9 @@
|
|||
error[E0107]: wrong number of type arguments: expected 2, found 1
|
||||
--> $DIR/issue-65159.rs:5:20
|
||||
|
|
||||
LL | async fn copy() -> Result<()>
|
||||
| ^^^^^^^^^^ expected 2 type arguments
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0107`.
|
42
src/test/ui/async-await/unused-lifetime.rs
Normal file
42
src/test/ui/async-await/unused-lifetime.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
// edition:2018
|
||||
|
||||
// Avoid spurious warnings of unused lifetime. The below async functions
|
||||
// are desugered to have an unused lifetime
|
||||
// but we don't want to warn about that as there's nothing they can do about it.
|
||||
|
||||
#![deny(unused_lifetimes)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub async fn october(s: &str) {
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
pub async fn async_fn(&mut ref s: &mut[i32]) {
|
||||
println!("{:?}", s);
|
||||
}
|
||||
|
||||
macro_rules! foo_macro {
|
||||
() => {
|
||||
pub async fn async_fn_in_macro(&mut ref _s: &mut[i32]) {}
|
||||
};
|
||||
}
|
||||
|
||||
foo_macro!();
|
||||
|
||||
pub async fn func_with_unused_lifetime<'a>(s: &'a str) {
|
||||
//~^ ERROR lifetime parameter `'a` never used
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
|
||||
//~^ ERROR lifetime parameter `'a` never used
|
||||
//~^^ ERROR lifetime parameter `'b` never used
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) {
|
||||
//~^ ERROR lifetime parameter `'c` never used
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
fn main() {}
|
32
src/test/ui/async-await/unused-lifetime.stderr
Normal file
32
src/test/ui/async-await/unused-lifetime.stderr
Normal file
|
@ -0,0 +1,32 @@
|
|||
error: lifetime parameter `'a` never used
|
||||
--> $DIR/unused-lifetime.rs:26:40
|
||||
|
|
||||
LL | pub async fn func_with_unused_lifetime<'a>(s: &'a str) {
|
||||
| ^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/unused-lifetime.rs:7:9
|
||||
|
|
||||
LL | #![deny(unused_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lifetime parameter `'a` never used
|
||||
--> $DIR/unused-lifetime.rs:31:44
|
||||
|
|
||||
LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
|
||||
| ^^
|
||||
|
||||
error: lifetime parameter `'b` never used
|
||||
--> $DIR/unused-lifetime.rs:31:48
|
||||
|
|
||||
LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
|
||||
| ^^
|
||||
|
||||
error: lifetime parameter `'c` never used
|
||||
--> $DIR/unused-lifetime.rs:37:54
|
||||
|
|
||||
LL | pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(unreachable_code)]
|
||||
|
|
23
src/test/ui/consts/issue-65348.rs
Normal file
23
src/test/ui/consts/issue-65348.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// check-pass
|
||||
|
||||
struct Generic<T>(T);
|
||||
|
||||
impl<T> Generic<T> {
|
||||
const ARRAY: [T; 0] = [];
|
||||
const NEWTYPE_ARRAY: Generic<[T; 0]> = Generic([]);
|
||||
const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, []));
|
||||
}
|
||||
|
||||
pub const fn array<T>() -> &'static T {
|
||||
&Generic::<T>::ARRAY[0]
|
||||
}
|
||||
|
||||
pub const fn newtype_array<T>() -> &'static T {
|
||||
&Generic::<T>::NEWTYPE_ARRAY.0[0]
|
||||
}
|
||||
|
||||
pub const fn array_field<T>() -> &'static T {
|
||||
&(Generic::<T>::ARRAY_FIELD.0).1[0]
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(never_type)]
|
||||
|
||||
fn foo() -> Result<u32, !> {
|
||||
Ok(123)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
|
||||
--> $DIR/feature-gate-exhaustive-patterns.rs:7:9
|
||||
--> $DIR/feature-gate-exhaustive-patterns.rs:8:9
|
||||
|
|
||||
LL | let Ok(_x) = foo();
|
||||
| ^^^^^^ pattern `Err(_)` not covered
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(unreachable_code)]
|
||||
#![feature(never_type)]
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#![crate_type="lib"]
|
||||
|
||||
struct Nested<K>(K);
|
||||
|
||||
fn should_error<T>() where T : Into<&u32> {}
|
||||
//~^ ERROR `&` without an explicit lifetime name cannot be used here [E0637]
|
||||
|
||||
trait X<'a, K: 'a> {
|
||||
fn foo<'b, L: X<&'b Nested<K>>>();
|
||||
//~^ ERROR missing lifetime specifier [E0106]
|
||||
}
|
||||
|
||||
fn bar<'b, L: X<&'b Nested<i32>>>(){}
|
||||
//~^ ERROR missing lifetime specifier [E0106]
|
|
@ -0,0 +1,21 @@
|
|||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:37
|
||||
|
|
||||
LL | fn should_error<T>() where T : Into<&u32> {}
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
|
||||
|
|
||||
LL | fn foo<'b, L: X<&'b Nested<K>>>();
|
||||
| ^^^^^^^^^^^^^^^^ expected lifetime parameter
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:15
|
||||
|
|
||||
LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
|
||||
| ^^^^^^^^^^^^^^^^^^ expected lifetime parameter
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
|
@ -6,3 +6,4 @@ LL | let p = foo { x: () };
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -6,3 +6,4 @@ LL | Foo { i } => ()
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -6,3 +6,4 @@ LL | let myVar = MyMod { T: 0 };
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -6,3 +6,4 @@ LL | let _ = module { x: 0 };
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -6,3 +6,4 @@ LL | char{ch} => true
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -24,3 +24,4 @@ LL | u32 { x: 1 } => {}
|
|||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -16,4 +16,5 @@ LL | Foo::f();
|
|||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
||||
Some errors have detailed explanations: E0574, E0599.
|
||||
For more information about an error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(never_type)]
|
||||
|
||||
#![deny(unused_must_use)]
|
||||
|
||||
#[must_use]
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
error: unused return value of `foo` that must be used
|
||||
--> $DIR/must_use-unit.rs:14:5
|
||||
--> $DIR/must_use-unit.rs:13:5
|
||||
|
|
||||
LL | foo();
|
||||
| ^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/must_use-unit.rs:3:9
|
||||
--> $DIR/must_use-unit.rs:2:9
|
||||
|
|
||||
LL | #![deny(unused_must_use)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: unused return value of `bar` that must be used
|
||||
--> $DIR/must_use-unit.rs:16:5
|
||||
--> $DIR/must_use-unit.rs:15:5
|
||||
|
|
||||
LL | bar();
|
||||
| ^^^^^^
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Test that a variable of type ! can coerce to another type.
|
||||
|
||||
// run-fail
|
||||
// error-pattern:explicit
|
||||
|
||||
#![feature(never_type)]
|
|
@ -1,5 +1,6 @@
|
|||
// Test that we can use a ! for an argument of type !
|
||||
|
||||
// run-fail
|
||||
// error-pattern:wowzers!
|
||||
|
||||
#![feature(never_type)]
|
|
@ -1,5 +1,6 @@
|
|||
// Test that we can explicitly cast ! to another type
|
||||
|
||||
// run-fail
|
||||
// error-pattern:explicit
|
||||
|
||||
#![feature(never_type)]
|
|
@ -4,6 +4,7 @@
|
|||
#![allow(unused_assignments)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
// Test various cases where we permit an unconstrained variable
|
||||
// to fallback based on control-flow.
|
||||
//
|
|
@ -1,8 +1,9 @@
|
|||
// run-pass
|
||||
// Test that we can call static methods on ! both directly and when it appears in a generic
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
// Test that we can call static methods on ! both directly and when it appears in a generic
|
||||
|
||||
trait StringifyType {
|
||||
fn stringify_type() -> &'static str;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
|
@ -1,9 +1,9 @@
|
|||
// Test that an assignment of type ! makes the rest of the block dead code.
|
||||
|
||||
#![feature(never_type)]
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
#![warn(unused)]
|
||||
// check-pass
|
||||
|
||||
#![feature(never_type)]
|
||||
#![warn(unused)]
|
||||
|
||||
fn main() {
|
||||
let x: ! = panic!("aah"); //~ WARN unused
|
|
@ -7,7 +7,7 @@ LL | drop(x);
|
|||
| ^^^^^^^^ unreachable statement
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/never-assign-dead-code.rs:5:9
|
||||
--> $DIR/never-assign-dead-code.rs:6:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
|
@ -29,7 +29,7 @@ LL | let x: ! = panic!("aah");
|
|||
| ^ help: consider prefixing with an underscore: `_x`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/never-assign-dead-code.rs:5:9
|
||||
--> $DIR/never-assign-dead-code.rs:6:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
|
@ -1,5 +1,6 @@
|
|||
// Test that we can use ! as an associated type.
|
||||
|
||||
// run-fail
|
||||
// error-pattern:kapow!
|
||||
|
||||
#![feature(never_type)]
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
// Test that we can extract a ! through pattern matching then use it as several different types.
|
||||
|
||||
#![feature(never_type)]
|
|
@ -1,5 +1,6 @@
|
|||
// Test that we can use ! as an argument to a trait impl.
|
||||
|
||||
// run-fail
|
||||
// error-pattern:oh no!
|
||||
|
||||
#![feature(never_type)]
|
|
@ -1,4 +1,4 @@
|
|||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// compile-fail
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
error: unreachable pattern
|
||||
--> $DIR/unreachable-loop-patterns.rs:20:9
|
||||
--> $DIR/unreachable-loop-patterns.rs:18:9
|
||||
|
|
||||
LL | for _ in unimplemented!() as Void {}
|
||||
| ^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/unreachable-loop-patterns.rs:7:9
|
||||
--> $DIR/unreachable-loop-patterns.rs:5:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable-loop-patterns.rs:20:14
|
||||
--> $DIR/unreachable-loop-patterns.rs:18:14
|
||||
|
|
||||
LL | for _ in unimplemented!() as Void {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
@ -1,4 +1,4 @@
|
|||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
#![feature(never_type, exhaustive_patterns)]
|
||||
#![warn(unreachable_code)]
|
||||
#![warn(unreachable_patterns)]
|
|
@ -14,3 +14,4 @@ LL | use std::thread::Result;
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
10
src/test/ui/save-analysis/issue-64659.rs
Normal file
10
src/test/ui/save-analysis/issue-64659.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// check-pass
|
||||
// compile-flags: -Zsave-analysis
|
||||
|
||||
trait Trait { type Assoc; }
|
||||
|
||||
fn main() {
|
||||
struct Data<T: Trait> {
|
||||
x: T::Assoc,
|
||||
}
|
||||
}
|
47
src/test/ui/suggestions/constrain-trait.fixed
Normal file
47
src/test/ui/suggestions/constrain-trait.fixed
Normal file
|
@ -0,0 +1,47 @@
|
|||
// run-rustfix
|
||||
// check-only
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Demo {
|
||||
a: String
|
||||
}
|
||||
|
||||
trait GetString {
|
||||
fn get_a(&self) -> &String;
|
||||
}
|
||||
|
||||
trait UseString: std::fmt::Debug + GetString {
|
||||
fn use_string(&self) {
|
||||
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
|
||||
}
|
||||
}
|
||||
|
||||
trait UseString2: GetString {
|
||||
fn use_string(&self) {
|
||||
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
|
||||
}
|
||||
}
|
||||
|
||||
impl GetString for Demo {
|
||||
fn get_a(&self) -> &String {
|
||||
&self.a
|
||||
}
|
||||
}
|
||||
|
||||
impl UseString for Demo {}
|
||||
impl UseString2 for Demo {}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Demo, UseString};
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let d = Demo { a: "test".to_string() };
|
||||
d.use_string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
47
src/test/ui/suggestions/constrain-trait.rs
Normal file
47
src/test/ui/suggestions/constrain-trait.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// run-rustfix
|
||||
// check-only
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Demo {
|
||||
a: String
|
||||
}
|
||||
|
||||
trait GetString {
|
||||
fn get_a(&self) -> &String;
|
||||
}
|
||||
|
||||
trait UseString: std::fmt::Debug {
|
||||
fn use_string(&self) {
|
||||
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
|
||||
}
|
||||
}
|
||||
|
||||
trait UseString2 {
|
||||
fn use_string(&self) {
|
||||
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
|
||||
}
|
||||
}
|
||||
|
||||
impl GetString for Demo {
|
||||
fn get_a(&self) -> &String {
|
||||
&self.a
|
||||
}
|
||||
}
|
||||
|
||||
impl UseString for Demo {}
|
||||
impl UseString2 for Demo {}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Demo, UseString};
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let d = Demo { a: "test".to_string() };
|
||||
d.use_string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
27
src/test/ui/suggestions/constrain-trait.stderr
Normal file
27
src/test/ui/suggestions/constrain-trait.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error[E0599]: no method named `get_a` found for type `&Self` in the current scope
|
||||
--> $DIR/constrain-trait.rs:15:31
|
||||
|
|
||||
LL | println!("{:?}", self.get_a());
|
||||
| ^^^^^ method not found in `&Self`
|
||||
|
|
||||
= help: items from traits can only be used if the type parameter is bounded by the trait
|
||||
help: the following trait defines an item `get_a`, perhaps you need to add another supertrait for it:
|
||||
|
|
||||
LL | trait UseString: std::fmt::Debug + GetString {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0599]: no method named `get_a` found for type `&Self` in the current scope
|
||||
--> $DIR/constrain-trait.rs:21:31
|
||||
|
|
||||
LL | println!("{:?}", self.get_a());
|
||||
| ^^^^^ method not found in `&Self`
|
||||
|
|
||||
= help: items from traits can only be used if the type parameter is bounded by the trait
|
||||
help: the following trait defines an item `get_a`, perhaps you need to add a supertrait for it:
|
||||
|
|
||||
LL | trait UseString2: GetString {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
|
@ -6,3 +6,4 @@ LL | TraitNotAStruct{ value: 0 };
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
|
@ -21,3 +21,4 @@ LL | let try_result: Option<_> = try {
|
|||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
33
src/test/ui/underscore-imports/hygiene-2.rs
Normal file
33
src/test/ui/underscore-imports/hygiene-2.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Make sure that underscore imports with different contexts can exist in the
|
||||
// same scope.
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
mod x {
|
||||
pub use std::ops::Deref as _;
|
||||
}
|
||||
|
||||
macro n() {
|
||||
pub use crate::x::*;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! p {
|
||||
() => { pub use crate::x::*; }
|
||||
}
|
||||
|
||||
macro m($y:ident) {
|
||||
mod $y {
|
||||
crate::n!(); // Reexport of `Deref` should not be imported in `main`
|
||||
crate::p!(); // Reexport of `Deref` should be imported into `main`
|
||||
}
|
||||
}
|
||||
|
||||
m!(y);
|
||||
|
||||
fn main() {
|
||||
use crate::y::*;
|
||||
(&()).deref();
|
||||
}
|
40
src/test/ui/underscore-imports/hygiene.rs
Normal file
40
src/test/ui/underscore-imports/hygiene.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Make sure that underscore imports have the same hygiene considerations as
|
||||
// other imports.
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
mod x {
|
||||
pub use std::ops::Deref as _;
|
||||
}
|
||||
|
||||
|
||||
macro glob_import() {
|
||||
pub use crate::x::*;
|
||||
}
|
||||
|
||||
macro underscore_import() {
|
||||
use std::ops::DerefMut as _;
|
||||
}
|
||||
|
||||
mod y {
|
||||
crate::glob_import!();
|
||||
crate::underscore_import!();
|
||||
}
|
||||
|
||||
macro create_module($y:ident) {
|
||||
mod $y {
|
||||
crate::glob_import!();
|
||||
crate::underscore_import!();
|
||||
}
|
||||
}
|
||||
|
||||
create_module!(z);
|
||||
|
||||
fn main() {
|
||||
use crate::y::*;
|
||||
use crate::z::*;
|
||||
glob_import!();
|
||||
underscore_import!();
|
||||
(&()).deref(); //~ ERROR no method named `deref`
|
||||
(&mut ()).deref_mut(); //~ ERROR no method named `deref_mut`
|
||||
}
|
27
src/test/ui/underscore-imports/hygiene.stderr
Normal file
27
src/test/ui/underscore-imports/hygiene.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error[E0599]: no method named `deref` found for type `&()` in the current scope
|
||||
--> $DIR/hygiene.rs:38:11
|
||||
|
|
||||
LL | (&()).deref();
|
||||
| ^^^^^ method not found in `&()`
|
||||
|
|
||||
= help: items from traits can only be used if the trait is in scope
|
||||
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
||||
|
|
||||
LL | use std::ops::Deref;
|
||||
|
|
||||
|
||||
error[E0599]: no method named `deref_mut` found for type `&mut ()` in the current scope
|
||||
--> $DIR/hygiene.rs:39:15
|
||||
|
|
||||
LL | (&mut ()).deref_mut();
|
||||
| ^^^^^^^^^ method not found in `&mut ()`
|
||||
|
|
||||
= help: items from traits can only be used if the trait is in scope
|
||||
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
||||
|
|
||||
LL | use std::ops::DerefMut;
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
45
src/test/ui/underscore-imports/macro-expanded.rs
Normal file
45
src/test/ui/underscore-imports/macro-expanded.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Check that macro expanded underscore imports behave as expected
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(decl_macro, rustc_attrs)]
|
||||
|
||||
mod x {
|
||||
pub use std::ops::Not as _;
|
||||
}
|
||||
|
||||
macro m() {
|
||||
mod w {
|
||||
mod y {
|
||||
pub use std::ops::Deref as _;
|
||||
}
|
||||
use crate::x::*;
|
||||
use self::y::*;
|
||||
use std::ops::DerefMut as _;
|
||||
fn f() {
|
||||
false.not();
|
||||
(&()).deref();
|
||||
(&mut ()).deref_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_macro_transparency = "transparent"]
|
||||
macro n() {
|
||||
mod z {
|
||||
pub use std::ops::Deref as _;
|
||||
}
|
||||
use crate::x::*;
|
||||
use crate::z::*;
|
||||
use std::ops::DerefMut as _;
|
||||
fn f() {
|
||||
false.not();
|
||||
(&()).deref();
|
||||
(&mut ()).deref_mut();
|
||||
}
|
||||
}
|
||||
|
||||
m!();
|
||||
n!();
|
||||
|
||||
fn main() {}
|
|
@ -6,3 +6,4 @@ LL | Trait { x: 42 } => ()
|
|||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0574`.
|
||||
|
|
Loading…
Add table
Reference in a new issue