Auto merge of #113188 - matthiaskrgr:rollup-j3abaks, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #107624 (Stabilize `const_cstr_methods`)
 - #111403 (suggest `slice::swap` for `mem::swap(&mut x[0], &mut x[1])` borrowck error)
 - #113071 (Account for late-bound vars from parent arg-position impl trait)
 - #113165 (Encode item bounds for `DefKind::ImplTraitPlaceholder`)
 - #113171 (Properly implement variances_of for RPITIT GAT)
 - #113177 (Use structured suggestion when telling user about `for<'a>`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-06-30 06:31:57 +00:00
commit b4591cb04c
32 changed files with 327 additions and 99 deletions

View file

@ -982,7 +982,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&msg_borrow,
None,
);
self.suggest_split_at_mut_if_applicable(
self.suggest_slice_method_if_applicable(
&mut err,
place,
issued_borrow.borrowed_place,
@ -1262,7 +1262,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
fn suggest_split_at_mut_if_applicable(
fn suggest_slice_method_if_applicable(
&self,
err: &mut Diagnostic,
place: Place<'tcx>,
@ -1274,7 +1274,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.help(
"consider using `.split_at_mut(position)` or similar method to obtain \
two mutable non-overlapping sub-slices",
);
)
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
}
}

View file

@ -99,6 +99,15 @@ hir_analysis_invalid_union_field =
hir_analysis_invalid_union_field_sugg =
wrap the field type in `ManuallyDrop<...>`
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
.label = const parameter declared here
hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetimes from an fn or impl
.label = lifetime declared here
hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
.label = type parameter declared here
hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait

View file

@ -1344,12 +1344,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Binder {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let mut err = self.tcx.sess.struct_span_err(
lifetime_ref.ident.span,
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
);
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
err.emit();
self.tcx.sess.emit_err(errors::LateBoundInApit::Lifetime {
span: lifetime_ref.ident.span,
param_span: self.tcx.def_span(region_def_id),
});
return;
}
Scope::Root { .. } => break,
@ -1379,6 +1377,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let mut late_depth = 0;
let mut scope = self.scope;
let mut crossed_anon_const = false;
let result = loop {
match *scope {
Scope::Body { s, .. } => {
@ -1446,6 +1445,50 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
return;
}
// We may fail to resolve higher-ranked ty/const vars that are mentioned by APIT.
// AST-based resolution does not care for impl-trait desugaring, which are the
// responsibility of lowering. This may create a mismatch between the resolution
// AST found (`param_def_id`) which points to HRTB, and what HIR allows.
// ```
// fn foo(x: impl for<T> Trait<Assoc = impl Trait2<T>>) {}
// ```
//
// In such case, walk back the binders to diagnose it properly.
let mut scope = self.scope;
loop {
match *scope {
Scope::Binder {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let guar = self.tcx.sess.emit_err(match self.tcx.def_kind(param_def_id) {
DefKind::TyParam => errors::LateBoundInApit::Type {
span: self.tcx.hir().span(hir_id),
param_span: self.tcx.def_span(param_def_id),
},
DefKind::ConstParam => errors::LateBoundInApit::Const {
span: self.tcx.hir().span(hir_id),
param_span: self.tcx.def_span(param_def_id),
},
kind => {
bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
}
});
self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
return;
}
Scope::Root { .. } => break,
Scope::Binder { s, .. }
| Scope::Body { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
}
self.tcx.sess.delay_span_bug(
self.tcx.hir().span(hir_id),
format!("could not resolve {param_def_id:?}"),

View file

@ -875,3 +875,28 @@ pub(crate) enum ReturnTypeNotationIllegalParam {
param_span: Span,
},
}
#[derive(Diagnostic)]
pub(crate) enum LateBoundInApit {
#[diag(hir_analysis_late_bound_type_in_apit)]
Type {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
#[diag(hir_analysis_late_bound_const_in_apit)]
Const {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
#[diag(hir_analysis_late_bound_lifetime_in_apit)]
Lifetime {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
}

View file

@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
use rustc_middle::ty::{self, CrateVariancesMap, ImplTraitInTraitData, SubstsRef, Ty, TyCtxt};
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
use std::ops::ControlFlow;
@ -51,20 +51,26 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
| DefKind::Struct
| DefKind::Union
| DefKind::Variant
| DefKind::Ctor(..) => {}
| DefKind::Ctor(..) => {
// These are inferred.
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
}
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
return variance_of_opaque(tcx, item_def_id);
}
_ => {
// Variance not relevant.
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item")
DefKind::AssocTy => {
if let Some(ImplTraitInTraitData::Trait { .. }) =
tcx.opt_rpitit_info(item_def_id.to_def_id())
{
return variance_of_opaque(tcx, item_def_id);
}
}
_ => {}
}
// Everything else must be inferred.
let crate_map = tcx.crate_variances(());
crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
// Variance not relevant.
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item");
}
#[instrument(level = "trace", skip(tcx), ret)]

View file

@ -1447,6 +1447,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
.is_type_alias_impl_trait
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
}
if let DefKind::ImplTraitPlaceholder = def_kind {
self.encode_explicit_item_bounds(def_id);
}
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
{

View file

@ -1632,9 +1632,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
..
} = &rib.kind
{
diag.span_help(
*span,
"consider introducing a higher-ranked lifetime here with `for<'a>`",
diag.multipart_suggestion(
"consider introducing a higher-ranked lifetime here",
vec![
(span.shrink_to_lo(), "for<'a> ".into()),
(lifetime.ident.span.shrink_to_hi(), "'a ".into()),
],
Applicability::MachineApplicable,
);
break;
}

View file

@ -241,7 +241,7 @@ impl CStr {
/// ```
///
/// ```
/// #![feature(const_cstr_methods)]
/// #![feature(const_cstr_from_ptr)]
///
/// use std::ffi::{c_char, CStr};
///
@ -256,7 +256,7 @@ impl CStr {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
#[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "101719")]
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
@ -377,7 +377,7 @@ impl CStr {
/// assert!(cstr.is_err());
/// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
#[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")]
pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
@ -561,10 +561,12 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_bytes(&self) -> &[u8] {
#[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")]
pub const fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
// FIXME(const-hack) replace with range index
// SAFETY: to_bytes_with_nul returns slice with length at least 1
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
unsafe { slice::from_raw_parts(bytes.as_ptr(), bytes.len() - 1) }
}
/// Converts this C string to a byte slice containing the trailing 0 byte.
@ -588,7 +590,7 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
#[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")]
pub const fn to_bytes_with_nul(&self) -> &[u8] {
// SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
// is safe on all supported targets.
@ -612,7 +614,8 @@ impl CStr {
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
#[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")]
pub const fn to_str(&self) -> Result<&str, str::Utf8Error> {
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
// instead of in `from_ptr()`, it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation

View file

@ -113,7 +113,6 @@
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_char_from_u32_unchecked)]
#![feature(const_cstr_methods)]
#![feature(const_discriminant)]
#![feature(const_eval_select)]
#![feature(const_exact_div)]

View file

@ -22,11 +22,10 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
LL | T: Into<&u32>,
| ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/E0637.rs:13:8
help: consider introducing a higher-ranked lifetime here
|
LL | T: Into<&u32>,
| ^
LL | T: for<'a> Into<&'a u32>,
| +++++++ ++
error: aborting due to 3 previous errors

View file

@ -4,11 +4,10 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
LL | fn should_error<T>() where T : Into<&u32> {}
| ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:32
help: consider introducing a higher-ranked lifetime here
|
LL | fn should_error<T>() where T : Into<&u32> {}
| ^
LL | fn should_error<T>() where T : for<'a> Into<&'a u32> {}
| +++++++ ++
error[E0106]: missing lifetime specifier
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20

View file

@ -14,6 +14,10 @@ impl Foo for Local {
fn bar(self) -> Arc<String> { Arc::new(String::new()) }
}
fn generic(f: impl Foo) {
let x = &*f.bar();
}
fn main() {
// Witness an RPITIT from another crate.
let &() = Foreign.bar();

View file

@ -0,0 +1,19 @@
// check-pass
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
// revisions: current next
#![feature(return_position_impl_trait_in_trait)]
trait Foo {}
impl Foo for () {}
trait ThreeCellFragment {
fn ext_cells<'a>(&'a self) -> impl Foo + 'a {
self.ext_adjacent_cells()
}
fn ext_adjacent_cells<'a>(&'a self) -> impl Foo + 'a;
}
fn main() {}

View file

@ -3,6 +3,6 @@ trait Trait<'a> {
}
fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
//~^ ERROR `impl Trait` can only mention lifetimes bound at the fn or impl level
//~^ ERROR `impl Trait` can only mention lifetimes from an fn or impl
fn main() {}

View file

@ -1,14 +1,8 @@
error: `impl Trait` can only mention lifetimes bound at the fn or impl level
error: `impl Trait` can only mention lifetimes from an fn or impl
--> $DIR/universal_wrong_hrtb.rs:5:73
|
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
| ^^
|
note: lifetime declared here
--> $DIR/universal_wrong_hrtb.rs:5:39
|
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
| ^^
| -- lifetime declared here ^^
error: aborting due to previous error

View file

@ -9,6 +9,7 @@ LL | *a = 5;
| ------ first borrow later used here
|
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
= help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
error: aborting due to previous error

View file

@ -0,0 +1,11 @@
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
trait Trait<Input> {
type Assoc;
}
fn uwu(_: impl for<T> Trait<(), Assoc = impl Trait<T>>) {}
//~^ ERROR `impl Trait` can only mention type parameters from an fn or impl
fn main() {}

View file

@ -0,0 +1,17 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/nested-apit-mentioning-outer-bound-var.rs:1:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= note: `#[warn(incomplete_features)]` on by default
error: `impl Trait` can only mention type parameters from an fn or impl
--> $DIR/nested-apit-mentioning-outer-bound-var.rs:8:52
|
LL | fn uwu(_: impl for<T> Trait<(), Assoc = impl Trait<T>>) {}
| - type parameter declared here ^
error: aborting due to previous error; 1 warning emitted

View file

@ -0,0 +1,17 @@
// run-rustfix
trait WithType<T> {}
trait WithRegion<'a> { }
#[allow(dead_code)]
struct Foo<T> {
t: T
}
impl<T> Foo<T>
where
T: for<'a> WithType<&'a u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -0,0 +1,17 @@
// run-rustfix
trait WithType<T> {}
trait WithRegion<'a> { }
#[allow(dead_code)]
struct Foo<T> {
t: T
}
impl<T> Foo<T>
where
T: WithType<&u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -1,14 +1,13 @@
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> $DIR/where-clause-trait-impl-region.rs:11:17
--> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:13:17
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-trait-impl-region.rs:11:8
help: consider introducing a higher-ranked lifetime here
|
LL | T: WithType<&u32>
| ^
LL | T: for<'a> WithType<&'a u32>
| +++++++ ++
error: aborting due to previous error

View file

@ -0,0 +1,18 @@
// edition:2018
// run-rustfix
trait WithType<T> {}
trait WithRegion<'a> { }
#[allow(dead_code)]
struct Foo<T> {
t: T
}
impl<T> Foo<T>
where
T: for<'a> WithType<&'a u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -0,0 +1,18 @@
// edition:2018
// run-rustfix
trait WithType<T> {}
trait WithRegion<'a> { }
#[allow(dead_code)]
struct Foo<T> {
t: T
}
impl<T> Foo<T>
where
T: WithType<&u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -1,14 +1,13 @@
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> $DIR/where-clause-trait-impl-region.rs:11:17
--> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:14:17
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-trait-impl-region.rs:11:8
help: consider introducing a higher-ranked lifetime here
|
LL | T: WithType<&u32>
| ^
LL | T: for<'a> WithType<&'a u32>
| +++++++ ++
error: aborting due to previous error

View file

@ -1,18 +0,0 @@
// revisions: rust2015 rust2018
//[rust2018] edition:2018
trait WithType<T> {}
trait WithRegion<'a> { }
struct Foo<T> {
t: T
}
impl<T> Foo<T>
where
T: WithType<&u32>
//[rust2015]~^ ERROR `&` without an explicit lifetime name cannot be used here
//[rust2018]~^^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -0,0 +1,14 @@
// run-rustfix
trait WithType<T> {}
trait WithRegion<'a> { }
trait Foo { }
impl<T> Foo for Vec<T>
where
T: for<'a> WithType<&'a u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -0,0 +1,14 @@
// run-rustfix
trait WithType<T> {}
trait WithRegion<'a> { }
trait Foo { }
impl<T> Foo for Vec<T>
where
T: WithType<&u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -1,14 +1,13 @@
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> $DIR/where-clause-inherent-impl-ampersand.rs:13:17
--> $DIR/where-clause-trait-impl-region-2015.rs:10:17
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
help: consider introducing a higher-ranked lifetime here
|
LL | T: WithType<&u32>
| ^
LL | T: for<'a> WithType<&'a u32>
| +++++++ ++
error: aborting due to previous error

View file

@ -0,0 +1,15 @@
// run-rustfix
// edition:2018
trait WithType<T> {}
trait WithRegion<'a> { }
trait Foo { }
impl<T> Foo for Vec<T>
where
T: for<'a> WithType<&'a u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -0,0 +1,15 @@
// run-rustfix
// edition:2018
trait WithType<T> {}
trait WithRegion<'a> { }
trait Foo { }
impl<T> Foo for Vec<T>
where
T: WithType<&u32>
//~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}

View file

@ -1,14 +1,13 @@
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> $DIR/where-clause-inherent-impl-ampersand.rs:13:17
--> $DIR/where-clause-trait-impl-region-2018.rs:11:17
|
LL | T: WithType<&u32>
| ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
help: consider introducing a higher-ranked lifetime here
|
LL | T: WithType<&u32>
| ^
LL | T: for<'a> WithType<&'a u32>
| +++++++ ++
error: aborting due to previous error

View file

@ -1,15 +0,0 @@
// revisions: rust2015 rust2018
//[rust2018] edition:2018
trait WithType<T> {}
trait WithRegion<'a> { }
trait Foo { }
impl<T> Foo for Vec<T>
where
T: WithType<&u32>
//[rust2015,rust2018]~^ ERROR `&` without an explicit lifetime name cannot be used here
{ }
fn main() {}