Auto merge of #116384 - matthiaskrgr:rollup-se332zs, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #114654 (Suggest `pin!()` instead of `Pin::new()` when appropriate) - #116261 (a small wf and clause cleanup) - #116282 (Fix broken links) - #116328 (Factor out common token generation in `fluent_messages`.) - #116379 (non_lifetime_binders: fix ICE in lint opaque-hidden-inferred-bound) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
268d625029
@ -40,26 +40,35 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tokens to be returned when the macro cannot proceed.
|
||||
fn failed(crate_name: &Ident) -> proc_macro::TokenStream {
|
||||
/// Final tokens.
|
||||
fn finish(body: TokenStream, resource: TokenStream) -> proc_macro::TokenStream {
|
||||
quote! {
|
||||
pub static DEFAULT_LOCALE_RESOURCE: &'static str = "";
|
||||
/// Raw content of Fluent resource for this crate, generated by `fluent_messages` macro,
|
||||
/// imported by `rustc_driver` to include all crates' resources in one bundle.
|
||||
pub static DEFAULT_LOCALE_RESOURCE: &'static str = #resource;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[doc(hidden)]
|
||||
/// Auto-generated constants for type-checked references to Fluent messages.
|
||||
pub(crate) mod fluent_generated {
|
||||
pub mod #crate_name {
|
||||
}
|
||||
#body
|
||||
|
||||
/// Constants expected to exist by the diagnostic derive macros to use as default Fluent
|
||||
/// identifiers for different subdiagnostic kinds.
|
||||
pub mod _subdiag {
|
||||
/// Default for `#[help]`
|
||||
pub const help: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
|
||||
/// Default for `#[note]`
|
||||
pub const note: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
|
||||
/// Default for `#[warn]`
|
||||
pub const warn: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn"));
|
||||
/// Default for `#[label]`
|
||||
pub const label: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
|
||||
/// Default for `#[suggestion]`
|
||||
pub const suggestion: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion"));
|
||||
}
|
||||
@ -68,6 +77,11 @@ pub mod _subdiag {
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Tokens to be returned when the macro cannot proceed.
|
||||
fn failed(crate_name: &Ident) -> proc_macro::TokenStream {
|
||||
finish(quote! { pub mod #crate_name {} }, quote! { "" })
|
||||
}
|
||||
|
||||
/// See [rustc_fluent_macro::fluent_messages].
|
||||
pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let crate_name = std::env::var("CARGO_PKG_NAME")
|
||||
@ -311,39 +325,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
/// Raw content of Fluent resource for this crate, generated by `fluent_messages` macro,
|
||||
/// imported by `rustc_driver` to include all crates' resources in one bundle.
|
||||
pub static DEFAULT_LOCALE_RESOURCE: &'static str = include_str!(#relative_ftl_path);
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[doc(hidden)]
|
||||
/// Auto-generated constants for type-checked references to Fluent messages.
|
||||
pub(crate) mod fluent_generated {
|
||||
#constants
|
||||
|
||||
/// Constants expected to exist by the diagnostic derive macros to use as default Fluent
|
||||
/// identifiers for different subdiagnostic kinds.
|
||||
pub mod _subdiag {
|
||||
/// Default for `#[help]`
|
||||
pub const help: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
|
||||
/// Default for `#[note]`
|
||||
pub const note: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
|
||||
/// Default for `#[warn]`
|
||||
pub const warn: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn"));
|
||||
/// Default for `#[label]`
|
||||
pub const label: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
|
||||
/// Default for `#[suggestion]`
|
||||
pub const suggestion: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion"));
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
finish(constants, quote! { include_str!(#relative_ftl_path) })
|
||||
}
|
||||
|
||||
fn variable_references<'a>(msg: &Message<&'a str>) -> Vec<&'a str> {
|
||||
|
@ -16,6 +16,7 @@
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::util::ExplicitSelf;
|
||||
use rustc_middle::ty::ToPredicate;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
@ -2279,16 +2280,16 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
//
|
||||
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
|
||||
}
|
||||
_ => predicates.push(ty::Clause::from_projection_clause(
|
||||
tcx,
|
||||
_ => predicates.push(
|
||||
ty::Binder::bind_with_vars(
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args),
|
||||
term: normalize_impl_ty.into(),
|
||||
},
|
||||
bound_vars,
|
||||
),
|
||||
)),
|
||||
)
|
||||
.to_predicate(tcx),
|
||||
),
|
||||
};
|
||||
ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
|
||||
};
|
||||
|
@ -1130,11 +1130,11 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
|
||||
let wf_obligations =
|
||||
bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| {
|
||||
let normalized_bound = wfcx.normalize(span, None, bound);
|
||||
traits::wf::predicate_obligations(
|
||||
traits::wf::clause_obligations(
|
||||
wfcx.infcx,
|
||||
wfcx.param_env,
|
||||
wfcx.body_def_id,
|
||||
normalized_bound.as_predicate(),
|
||||
normalized_bound,
|
||||
bound_span,
|
||||
)
|
||||
});
|
||||
@ -1234,7 +1234,7 @@ fn check_impl<'tcx>(
|
||||
wfcx.infcx,
|
||||
wfcx.param_env,
|
||||
wfcx.body_def_id,
|
||||
&trait_pred,
|
||||
trait_pred,
|
||||
ast_trait_ref.path.span,
|
||||
item,
|
||||
);
|
||||
@ -1443,13 +1443,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!(?predicates.predicates);
|
||||
assert_eq!(predicates.predicates.len(), predicates.spans.len());
|
||||
let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
|
||||
traits::wf::predicate_obligations(
|
||||
infcx,
|
||||
wfcx.param_env,
|
||||
wfcx.body_def_id,
|
||||
p.as_predicate(),
|
||||
sp,
|
||||
)
|
||||
traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp)
|
||||
});
|
||||
let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
|
||||
wfcx.register_obligations(obligations);
|
||||
|
@ -376,9 +376,9 @@ fn check_predicates<'tcx>(
|
||||
let always_applicable_traits = impl1_predicates
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|(clause, _span)| {
|
||||
.filter(|&(clause, _span)| {
|
||||
matches!(
|
||||
trait_predicate_kind(tcx, clause.as_predicate()),
|
||||
trait_specialization_kind(tcx, clause),
|
||||
Some(TraitSpecializationKind::AlwaysApplicable)
|
||||
)
|
||||
})
|
||||
@ -402,7 +402,7 @@ fn check_predicates<'tcx>(
|
||||
.iter()
|
||||
.any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
|
||||
{
|
||||
check_specialization_on(tcx, clause.as_predicate(), span)
|
||||
check_specialization_on(tcx, clause, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -441,19 +441,16 @@ fn trait_predicates_eq<'tcx>(
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) {
|
||||
match predicate.kind().skip_binder() {
|
||||
fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) {
|
||||
match clause.kind().skip_binder() {
|
||||
// Global predicates are either always true or always false, so we
|
||||
// are fine to specialize on.
|
||||
_ if predicate.is_global() => (),
|
||||
_ if clause.is_global() => (),
|
||||
// We allow specializing on explicitly marked traits with no associated
|
||||
// items.
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: _,
|
||||
})) => {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
|
||||
if !matches!(
|
||||
trait_predicate_kind(tcx, predicate),
|
||||
trait_specialization_kind(tcx, clause),
|
||||
Some(TraitSpecializationKind::Marker)
|
||||
) {
|
||||
tcx.sess
|
||||
@ -467,10 +464,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_ty,
|
||||
term,
|
||||
})) => {
|
||||
ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
span,
|
||||
@ -478,7 +472,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => {
|
||||
ty::ClauseKind::ConstArgHasType(..) => {
|
||||
// FIXME(min_specialization), FIXME(const_generics):
|
||||
// It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
|
||||
// about the actual rules that would be sound. Can't just always error here because otherwise
|
||||
@ -490,33 +484,25 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
||||
}
|
||||
_ => {
|
||||
tcx.sess
|
||||
.struct_span_err(span, format!("cannot specialize on predicate `{predicate}`"))
|
||||
.struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_predicate_kind<'tcx>(
|
||||
fn trait_specialization_kind<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
clause: ty::Clause<'tcx>,
|
||||
) -> Option<TraitSpecializationKind> {
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: _,
|
||||
})) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
| ty::PredicateKind::Coerce(_)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous => None,
|
||||
match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
|
||||
Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
|
||||
}
|
||||
ty::ClauseKind::RegionOutlives(_)
|
||||
| ty::ClauseKind::TypeOutlives(_)
|
||||
| ty::ClauseKind::Projection(_)
|
||||
| ty::ClauseKind::ConstArgHasType(..)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(..) => None,
|
||||
}
|
||||
}
|
||||
|
@ -2494,10 +2494,18 @@ fn suggest_traits_to_import(
|
||||
// Try alternative arbitrary self types that could fulfill this call.
|
||||
// FIXME: probe for all types that *could* be arbitrary self-types, not
|
||||
// just this list.
|
||||
for (rcvr_ty, post) in &[
|
||||
(rcvr_ty, ""),
|
||||
(Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
|
||||
(Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
|
||||
for (rcvr_ty, post, pin_call) in &[
|
||||
(rcvr_ty, "", None),
|
||||
(
|
||||
Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
|
||||
"&mut ",
|
||||
Some("as_mut"),
|
||||
),
|
||||
(
|
||||
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
|
||||
"&",
|
||||
Some("as_ref"),
|
||||
),
|
||||
] {
|
||||
match self.lookup_probe_for_diagnostic(
|
||||
item_name,
|
||||
@ -2531,6 +2539,17 @@ fn suggest_traits_to_import(
|
||||
Err(_) => (),
|
||||
}
|
||||
|
||||
let pred = ty::TraitRef::new(
|
||||
self.tcx,
|
||||
self.tcx.lang_items().unpin_trait().unwrap(),
|
||||
[*rcvr_ty],
|
||||
);
|
||||
let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
|
||||
self.tcx,
|
||||
ObligationCause::misc(rcvr.span, self.body_id),
|
||||
self.param_env,
|
||||
pred,
|
||||
));
|
||||
for (rcvr_ty, pre) in &[
|
||||
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
|
||||
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
|
||||
@ -2554,7 +2573,7 @@ fn suggest_traits_to_import(
|
||||
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
|
||||
// implement the `AsRef` trait.
|
||||
let skip = skippable.contains(&did)
|
||||
|| (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
|
||||
|| (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin))
|
||||
|| inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
|
||||
// Make sure the method is defined for the *actual* receiver: we don't
|
||||
// want to treat `Box<Self>` as a receiver if it only works because of
|
||||
@ -2566,7 +2585,7 @@ fn suggest_traits_to_import(
|
||||
);
|
||||
err.multipart_suggestion(
|
||||
"consider wrapping the receiver expression with the \
|
||||
appropriate type",
|
||||
appropriate type",
|
||||
vec![
|
||||
(rcvr.span.shrink_to_lo(), format!("{pre}({post}")),
|
||||
(rcvr.span.shrink_to_hi(), ")".to_string()),
|
||||
@ -2578,6 +2597,49 @@ fn suggest_traits_to_import(
|
||||
}
|
||||
}
|
||||
}
|
||||
// We special case the situation where `Pin::new` wouldn't work, and instead
|
||||
// suggest using the `pin!()` macro instead.
|
||||
if let Some(new_rcvr_t) = Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin)
|
||||
// We didn't find an alternative receiver for the method.
|
||||
&& !alt_rcvr_sugg
|
||||
// `T: !Unpin`
|
||||
&& !unpin
|
||||
// The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`.
|
||||
&& sym::as_ref != item_name.name
|
||||
// Either `Pin::as_ref` or `Pin::as_mut`.
|
||||
&& let Some(pin_call) = pin_call
|
||||
// Search for `item_name` as a method accessible on `Pin<T>`.
|
||||
&& let Ok(pick) = self.lookup_probe_for_diagnostic(
|
||||
item_name,
|
||||
new_rcvr_t,
|
||||
rcvr,
|
||||
ProbeScope::AllTraits,
|
||||
return_type,
|
||||
)
|
||||
// We skip some common traits that we don't want to consider because autoderefs
|
||||
// would take care of them.
|
||||
&& !skippable.contains(&Some(pick.item.container_id(self.tcx)))
|
||||
// We don't want to go through derefs.
|
||||
&& pick.autoderefs == 0
|
||||
// Check that the method of the same name that was found on the new `Pin<T>`
|
||||
// receiver has the same number of arguments that appear in the user's code.
|
||||
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
|
||||
{
|
||||
let indent = self.tcx.sess
|
||||
.source_map()
|
||||
.indentation_before(rcvr.span)
|
||||
.unwrap_or_else(|| " ".to_string());
|
||||
err.multipart_suggestion(
|
||||
"consider pinning the expression",
|
||||
vec![
|
||||
(rcvr.span.shrink_to_lo(), format!("let mut pinned = std::pin::pin!(")),
|
||||
(rcvr.span.shrink_to_hi(), format!(");\n{indent}pinned.{pin_call}()")),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
// We don't care about the other suggestions.
|
||||
alt_rcvr_sugg = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
|
||||
|
@ -37,8 +37,6 @@
|
||||
/// type Assoc: Duh;
|
||||
/// }
|
||||
///
|
||||
/// struct Struct;
|
||||
///
|
||||
/// impl<F: Duh> Trait for F {
|
||||
/// type Assoc = F;
|
||||
/// }
|
||||
@ -53,12 +51,12 @@
|
||||
/// {{produces}}
|
||||
///
|
||||
/// In this example, `test` declares that the associated type `Assoc` for
|
||||
/// `impl Trait` is `impl Sized`, which does not satisfy the `Send` bound
|
||||
/// `impl Trait` is `impl Sized`, which does not satisfy the bound `Duh`
|
||||
/// on the associated type.
|
||||
///
|
||||
/// Although the hidden type, `i32` does satisfy this bound, we do not
|
||||
/// consider the return type to be well-formed with this lint. It can be
|
||||
/// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`.
|
||||
/// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Duh`.
|
||||
pub OPAQUE_HIDDEN_INFERRED_BOUND,
|
||||
Warn,
|
||||
"detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
|
||||
@ -79,9 +77,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
for (pred, pred_span) in
|
||||
cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
|
||||
{
|
||||
// Liberate bound regions in the predicate since we
|
||||
// don't actually care about lifetimes in this check.
|
||||
let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
|
||||
let predicate = infcx.instantiate_binder_with_placeholders(pred.kind());
|
||||
let ty::ClauseKind::Projection(proj) = predicate else {
|
||||
continue;
|
||||
};
|
||||
|
@ -23,10 +23,10 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Now `LOG=debug cargo run` will run your minimal main.rs and show
|
||||
//! Now `LOG=debug cargo +nightly run` will run your minimal main.rs and show
|
||||
//! rustc's debug logging. In a workflow like this, one might also add
|
||||
//! `std::env::set_var("LOG", "debug")` to the top of main so that `cargo
|
||||
//! run` by itself is sufficient to get logs.
|
||||
//! +nightly run` by itself is sufficient to get logs.
|
||||
//!
|
||||
//! The reason rustc_log is a tiny separate crate, as opposed to exposing the
|
||||
//! same things in rustc_driver only, is to enable the above workflow. If you
|
||||
|
@ -578,11 +578,6 @@ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>);
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
pub fn from_projection_clause(tcx: TyCtxt<'tcx>, pred: PolyProjectionPredicate<'tcx>) -> Self {
|
||||
let pred: Predicate<'tcx> = pred.to_predicate(tcx);
|
||||
pred.expect_clause()
|
||||
}
|
||||
|
||||
pub fn as_predicate(self) -> Predicate<'tcx> {
|
||||
Predicate(self.0)
|
||||
}
|
||||
@ -1296,12 +1291,25 @@ fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
@ -1340,9 +1348,10 @@ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx)
|
||||
impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
let p: Predicate<'tcx> = self.to_predicate(tcx);
|
||||
p.expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,7 +725,7 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'
|
||||
self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
|
||||
}
|
||||
ExistentialPredicate::Projection(p) => {
|
||||
ty::Clause::from_projection_clause(tcx, self.rebind(p.with_self_ty(tcx, self_ty)))
|
||||
self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
|
||||
}
|
||||
ExistentialPredicate::AutoTrait(did) => {
|
||||
let generics = tcx.generics_of(did);
|
||||
|
@ -3,7 +3,7 @@
|
||||
// This target if is for the Android v7a ABI in thumb mode with
|
||||
// NEON unconditionally enabled and, therefore, with 32 FPU registers
|
||||
// enabled as well. See section A2.6.2 on page A2-56 in
|
||||
// https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
|
||||
// https://web.archive.org/web/20210307234416/https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
|
||||
|
||||
// See https://developer.android.com/ndk/guides/abis.html#v7a
|
||||
// for target ABI requirements.
|
||||
|
@ -4,7 +4,7 @@
|
||||
// (for consistency with Android and Debian-based distributions)
|
||||
// and with NEON unconditionally enabled and, therefore, with 32 FPU
|
||||
// registers enabled as well. See section A2.6.2 on page A2-56 in
|
||||
// https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
|
||||
// https://web.archive.org/web/20210307234416/https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
|
||||
|
||||
pub fn target() -> Target {
|
||||
Target {
|
||||
|
@ -4,7 +4,7 @@
|
||||
// (for consistency with Android and Debian-based distributions)
|
||||
// and with NEON unconditionally enabled and, therefore, with 32 FPU
|
||||
// registers enabled as well. See section A2.6.2 on page A2-56 in
|
||||
// https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
|
||||
// https://web.archive.org/web/20210307234416/https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
|
||||
|
||||
pub fn target() -> Target {
|
||||
Target {
|
||||
|
@ -346,14 +346,13 @@ fn consider_builtin_fn_trait_candidates(
|
||||
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
|
||||
});
|
||||
|
||||
let pred = ty::Clause::from_projection_clause(
|
||||
tcx,
|
||||
tupled_inputs_and_output.map_bound(|(inputs, output)| ty::ProjectionPredicate {
|
||||
let pred = tupled_inputs_and_output
|
||||
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
|
||||
projection_ty: tcx
|
||||
.mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
|
||||
term: output.into(),
|
||||
}),
|
||||
);
|
||||
})
|
||||
.to_predicate(tcx);
|
||||
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
|
@ -1644,7 +1644,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||
let env_predicates = data
|
||||
.projection_bounds()
|
||||
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
|
||||
.map(|p| ty::Clause::from_projection_clause(tcx, p.with_self_ty(tcx, object_ty)));
|
||||
.map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
|
||||
|
||||
assemble_candidates_from_predicates(
|
||||
selcx,
|
||||
|
@ -105,13 +105,13 @@ pub fn unnormalized_obligations<'tcx>(
|
||||
|
||||
/// Returns the obligations that make this trait reference
|
||||
/// well-formed. For example, if there is a trait `Set` defined like
|
||||
/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
|
||||
/// `trait Set<K: Eq>`, then the trait bound `Foo: Set<Bar>` is WF
|
||||
/// if `Bar: Eq`.
|
||||
pub fn trait_obligations<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
trait_pred: &ty::TraitPredicate<'tcx>,
|
||||
trait_pred: ty::TraitPredicate<'tcx>,
|
||||
span: Span,
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
@ -129,12 +129,17 @@ pub fn trait_obligations<'tcx>(
|
||||
wf.normalize(infcx)
|
||||
}
|
||||
|
||||
/// Returns the requirements for `clause` to be well-formed.
|
||||
///
|
||||
/// For example, if there is a trait `Set` defined like
|
||||
/// `trait Set<K: Eq>`, then the trait bound `Foo: Set<Bar>` is WF
|
||||
/// if `Bar: Eq`.
|
||||
#[instrument(skip(infcx), ret)]
|
||||
pub fn predicate_obligations<'tcx>(
|
||||
pub fn clause_obligations<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
clause: ty::Clause<'tcx>,
|
||||
span: Span,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
let mut wf = WfPredicates {
|
||||
@ -148,45 +153,32 @@ pub fn predicate_obligations<'tcx>(
|
||||
};
|
||||
|
||||
// It's ok to skip the binder here because wf code is prepared for it
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
|
||||
wf.compute_trait_pred(&t, Elaborate::None);
|
||||
match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(t) => {
|
||||
wf.compute_trait_pred(t, Elaborate::None);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty,
|
||||
_reg,
|
||||
))) => {
|
||||
ty::ClauseKind::RegionOutlives(..) => {}
|
||||
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
|
||||
wf.compute(ty.into());
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(t)) => {
|
||||
ty::ClauseKind::Projection(t) => {
|
||||
wf.compute_projection(t.projection_ty);
|
||||
wf.compute(match t.term.unpack() {
|
||||
ty::TermKind::Ty(ty) => ty.into(),
|
||||
ty::TermKind::Const(c) => c.into(),
|
||||
})
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||
ty::ClauseKind::ConstArgHasType(ct, ty) => {
|
||||
wf.compute(ct.into());
|
||||
wf.compute(ty.into());
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
ty::ClauseKind::WellFormed(arg) => {
|
||||
wf.compute(arg);
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
|
||||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
wf.compute(ct.into());
|
||||
}
|
||||
|
||||
ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}")
|
||||
}
|
||||
}
|
||||
|
||||
wf.normalize(infcx)
|
||||
@ -233,7 +225,7 @@ enum Elaborate {
|
||||
|
||||
fn extend_cause_with_original_assoc_item_obligation<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: &ty::TraitRef<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
item: Option<&hir::Item<'tcx>>,
|
||||
cause: &mut traits::ObligationCause<'tcx>,
|
||||
pred: ty::Predicate<'tcx>,
|
||||
@ -336,9 +328,9 @@ fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'
|
||||
}
|
||||
|
||||
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
|
||||
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
||||
fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
||||
let tcx = self.tcx();
|
||||
let trait_ref = &trait_pred.trait_ref;
|
||||
let trait_ref = trait_pred.trait_ref;
|
||||
|
||||
// Negative trait predicates don't require supertraits to hold, just
|
||||
// that their args are WF.
|
||||
@ -411,7 +403,7 @@ fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborat
|
||||
|
||||
// Compute the obligations that are required for `trait_ref` to be WF,
|
||||
// given that it is a *negative* trait predicate.
|
||||
fn compute_negative_trait_pred(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
|
||||
fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
|
||||
for arg in trait_ref.args {
|
||||
self.compute(arg);
|
||||
}
|
||||
|
@ -3,9 +3,8 @@
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{
|
||||
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||
};
|
||||
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitor};
|
||||
use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable};
|
||||
use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits;
|
||||
@ -214,10 +213,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||
// strategy, then just reinterpret the associated type like an opaque :^)
|
||||
let default_ty = self.tcx.type_of(shifted_alias_ty.def_id).instantiate(self.tcx, shifted_alias_ty.args);
|
||||
|
||||
self.predicates.push(ty::Clause::from_projection_clause(self.tcx, ty::Binder::bind_with_vars(
|
||||
self.predicates.push(ty::Binder::bind_with_vars(
|
||||
ty::ProjectionPredicate { projection_ty: shifted_alias_ty, term: default_ty.into() },
|
||||
self.bound_vars,
|
||||
)));
|
||||
).to_predicate(self.tcx));
|
||||
|
||||
// We walk the *un-shifted* alias ty, because we're tracking the de bruijn
|
||||
// binder depth, and if we were to walk `shifted_alias_ty` instead, we'd
|
||||
|
@ -95,7 +95,7 @@
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
|
||||
// ARM EHABI personality routine.
|
||||
// https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
|
||||
// https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
|
||||
//
|
||||
// iOS uses the default routine instead since it uses SjLj unwinding.
|
||||
#[lang = "eh_personality"]
|
||||
|
16
tests/ui/async-await/issue-108572.fixed
Normal file
16
tests/ui/async-await/issue-108572.fixed
Normal file
@ -0,0 +1,16 @@
|
||||
// edition: 2021
|
||||
// run-rustfix
|
||||
#![allow(unused_must_use, dead_code)]
|
||||
|
||||
use std::future::Future;
|
||||
fn foo() -> impl Future<Output=()> {
|
||||
async { }
|
||||
}
|
||||
|
||||
fn bar(cx: &mut std::task::Context<'_>) {
|
||||
let fut = foo();
|
||||
let mut pinned = std::pin::pin!(fut);
|
||||
pinned.as_mut().poll(cx);
|
||||
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
|
||||
}
|
||||
fn main() {}
|
@ -1,12 +1,15 @@
|
||||
// edition: 2021
|
||||
// run-rustfix
|
||||
#![allow(unused_must_use, dead_code)]
|
||||
|
||||
use std::future::Future;
|
||||
fn foo() -> impl Future<Output=()> {
|
||||
async { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn bar(cx: &mut std::task::Context<'_>) {
|
||||
let fut = foo();
|
||||
fut.poll();
|
||||
fut.poll(cx);
|
||||
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -1,11 +1,16 @@
|
||||
error[E0599]: no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
|
||||
--> $DIR/issue-108572.rs:10:9
|
||||
--> $DIR/issue-108572.rs:12:9
|
||||
|
|
||||
LL | fut.poll();
|
||||
LL | fut.poll(cx);
|
||||
| ^^^^ method not found in `impl Future<Output = ()>`
|
||||
|
|
||||
= help: method `poll` found on `Pin<&mut impl Future<Output = ()>>`, see documentation for `std::pin::Pin`
|
||||
= help: self type must be pinned to call `Future::poll`, see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice
|
||||
help: consider pinning the expression
|
||||
|
|
||||
LL ~ let mut pinned = std::pin::pin!(fut);
|
||||
LL ~ pinned.as_mut().poll(cx);
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,14 +6,12 @@ LL | struct Sleep;
|
||||
...
|
||||
LL | self.sleep.poll(cx)
|
||||
| ^^^^ method not found in `Sleep`
|
||||
--> $SRC_DIR/core/src/future/future.rs:LL:COL
|
||||
|
|
||||
= note: the method is available for `Pin<&mut Sleep>` here
|
||||
help: consider pinning the expression
|
||||
|
|
||||
help: consider wrapping the receiver expression with the appropriate type
|
||||
LL ~ let mut pinned = std::pin::pin!(self.sleep);
|
||||
LL ~ pinned.as_mut().poll(cx)
|
||||
|
|
||||
LL | Pin::new(&mut self.sleep).poll(cx)
|
||||
| +++++++++++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -8,5 +8,6 @@ impl S {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Pin::new(&mut S).x(); //~ ERROR no method named `x` found
|
||||
let mut pinned = std::pin::pin!(S);
|
||||
pinned.as_mut().x(); //~ ERROR no method named `x` found
|
||||
}
|
||||
|
@ -4,16 +4,14 @@ error[E0599]: no method named `x` found for struct `S` in the current scope
|
||||
LL | struct S;
|
||||
| -------- method `x` not found for this struct
|
||||
...
|
||||
LL | fn x(self: Pin<&mut Self>) {
|
||||
| - the method is available for `Pin<&mut S>` here
|
||||
...
|
||||
LL | S.x();
|
||||
| ^ method not found in `S`
|
||||
|
|
||||
help: consider wrapping the receiver expression with the appropriate type
|
||||
help: consider pinning the expression
|
||||
|
|
||||
LL ~ let mut pinned = std::pin::pin!(S);
|
||||
LL ~ pinned.as_mut().x();
|
||||
|
|
||||
LL | Pin::new(&mut S).x();
|
||||
| +++++++++++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
16
tests/ui/traits/non_lifetime_binders/on-rpit.rs
Normal file
16
tests/ui/traits/non_lifetime_binders/on-rpit.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(non_lifetime_binders)]
|
||||
//~^ WARN the feature `non_lifetime_binders` is incomplete
|
||||
|
||||
trait Trait<T: ?Sized> {}
|
||||
|
||||
impl<T: ?Sized> Trait<T> for i32 {}
|
||||
|
||||
fn produce() -> impl for<T> Trait<T> {
|
||||
16
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = produce();
|
||||
}
|
11
tests/ui/traits/non_lifetime_binders/on-rpit.stderr
Normal file
11
tests/ui/traits/non_lifetime_binders/on-rpit.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/on-rpit.rs:3: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
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
Loading…
Reference in New Issue
Block a user