Skip to content

Commit

Permalink
Auto merge of #116384 - matthiaskrgr:rollup-se332zs, r=matthiaskrgr
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Oct 3, 2023
2 parents e3c631b + 9143370 commit 268d625
Show file tree
Hide file tree
Showing 25 changed files with 242 additions and 174 deletions.
58 changes: 20 additions & 38 deletions compiler/rustc_fluent_macro/src/fluent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
Expand All @@ -68,6 +77,11 @@ fn failed(crate_name: &Ident) -> proc_macro::TokenStream {
.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")
Expand Down Expand Up @@ -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> {
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rustc_infer::traits::util;
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,
};
Expand Down Expand Up @@ -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)
};
Expand Down
14 changes: 4 additions & 10 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
});
Expand Down Expand Up @@ -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,
);
Expand Down Expand Up @@ -1443,13 +1443,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
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);
Expand Down
60 changes: 23 additions & 37 deletions compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
})
Expand All @@ -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)
}
}
}
Expand Down Expand Up @@ -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
Expand All @@ -467,18 +464,15 @@ 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,
format!("cannot specialize on associated type `{projection_ty} == {term}`",),
)
.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
Expand All @@ -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,
}
}
74 changes: 68 additions & 6 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2494,10 +2494,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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,
Expand Down Expand Up @@ -2531,6 +2539,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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"),
Expand All @@ -2554,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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
Expand All @@ -2566,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
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()),
Expand All @@ -2578,6 +2597,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
// 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) {
Expand Down
Loading

0 comments on commit 268d625

Please sign in to comment.