1
Fork 0

Auto merge of #121252 - fmease:rollup-x7zogl8, r=fmease

Rollup of 7 pull requests

Successful merges:

 - #120526 (rustdoc: Correctly handle long crate names on mobile)
 - #121100 (Detect when method call on argument could be removed to fulfill failed trait bound)
 - #121160 (rustdoc: fix and refactor HTML rendering a bit)
 - #121198 (Add more checks for `unnamed_fields` during HIR analysis)
 - #121218 (Fix missing trait impls for type in rustc docs)
 - #121221 (AstConv: Refactor lowering of associated item bindings a bit)
 - #121237 (Use better heuristic for printing Cargo specific diagnostics)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-18 06:02:16 +00:00
commit 23a3d777c8
41 changed files with 678 additions and 498 deletions

View file

@ -9,9 +9,7 @@ use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
use smallvec::SmallVec;
use crate::astconv::{
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
};
use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
use crate::bounds::Bounds;
use crate::errors;
@ -238,7 +236,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
&self,
hir_ref_id: hir::HirId,
trait_ref: ty::PolyTraitRef<'tcx>,
binding: &ConvertedBinding<'_, 'tcx>,
binding: &hir::TypeBinding<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
dup_bindings: &mut FxIndexMap<DefId, Span>,
@ -263,21 +261,20 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();
let assoc_kind =
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
ty::AssocKind::Fn
} else if let ConvertedBindingKind::Equality(term) = binding.kind
&& let ty::TermKind::Const(_) = term.node.unpack()
{
ty::AssocKind::Const
} else {
ty::AssocKind::Type
};
let assoc_kind = if binding.gen_args.parenthesized
== hir::GenericArgsParentheses::ReturnTypeNotation
{
ty::AssocKind::Fn
} else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind {
ty::AssocKind::Const
} else {
ty::AssocKind::Type
};
let candidate = if self.trait_defines_associated_item_named(
trait_ref.def_id(),
assoc_kind,
binding.item_name,
binding.ident,
) {
// Simple case: The assoc item is defined in the current trait.
trait_ref
@ -289,14 +286,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
trait_ref.skip_binder().print_only_trait_name(),
None,
assoc_kind,
binding.item_name,
binding.ident,
path_span,
Some(&binding),
Some(binding),
)?
};
let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id);
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
@ -312,7 +309,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
.dcx()
.struct_span_err(
binding.span,
format!("{} `{}` is private", assoc_item.kind, binding.item_name),
format!("{} `{}` is private", assoc_item.kind, binding.ident),
)
.with_span_label(binding.span, format!("private {}", assoc_item.kind))
.emit();
@ -327,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
span: binding.span,
prev_span: *prev_span,
item_name: binding.item_name,
item_name: binding.ident,
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
});
})
@ -390,14 +387,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
{
alias_ty
} else {
return Err(self.tcx().dcx().emit_err(
crate::errors::ReturnTypeNotationOnNonRpitit {
span: binding.span,
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
note: (),
},
));
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
span: binding.span,
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
note: (),
}));
};
// Finally, move the fn return type's bound vars over to account for the early bound
@ -410,9 +405,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let bound_vars = tcx.late_bound_vars(binding.hir_id);
ty::Binder::bind_with_vars(instantiation_output, bound_vars)
} else {
// Append the generic arguments of the associated type to the `trait_ref`.
// Create the generic arguments for the associated type or constant by joining the
// parent arguments (the arguments of the trait) and the own arguments (the ones of
// the associated item itself) and construct an alias type using them.
candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let ident = Ident::new(assoc_item.name, binding.ident.span);
let item_segment = hir::PathSegment {
ident,
hir_id: binding.hir_id,
@ -421,77 +418,82 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
infer_args: false,
};
let args_trait_ref_and_assoc_item = self.create_args_for_associated_item(
let alias_args = self.create_args_for_associated_item(
path_span,
assoc_item.def_id,
&item_segment,
trait_ref.args,
);
debug!(?alias_args);
debug!(?args_trait_ref_and_assoc_item);
ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item)
// Note that we're indeed also using `AliasTy` (alias *type*) for associated
// *constants* to represent *const projections*. Alias *term* would be a more
// appropriate name but alas.
ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
})
};
if !speculative {
// Find any late-bound regions declared in `ty` that are not
// declared in the trait-ref or assoc_item. These are not well-formed.
//
// Example:
//
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
if let ConvertedBindingKind::Equality(ty) = binding.kind {
let late_bound_in_trait_ref =
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
debug!(?late_bound_in_trait_ref);
debug!(?late_bound_in_ty);
// FIXME: point at the type params that don't have appropriate lifetimes:
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
// ---- ---- ^^^^^^^
self.validate_late_bound_regions(
late_bound_in_trait_ref,
late_bound_in_ty,
|br_name| {
struct_span_code_err!(
tcx.dcx(),
binding.span,
E0582,
"binding for associated type `{}` references {}, \
which does not appear in the trait input types",
binding.item_name,
br_name
)
},
);
}
}
match binding.kind {
ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
return Err(self.tcx().dcx().emit_err(
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
));
hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
span: binding.span,
}));
}
ConvertedBindingKind::Equality(term) => {
hir::TypeBindingKind::Equality { term } => {
let term = match term {
hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
};
if !speculative {
// Find any late-bound regions declared in `ty` that are not
// declared in the trait-ref or assoc_item. These are not well-formed.
//
// Example:
//
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
let late_bound_in_projection_ty =
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_term =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term));
debug!(?late_bound_in_projection_ty);
debug!(?late_bound_in_term);
// FIXME: point at the type params that don't have appropriate lifetimes:
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
// ---- ---- ^^^^^^^
// NOTE(associated_const_equality): This error should be impossible to trigger
// with associated const equality bounds.
self.validate_late_bound_regions(
late_bound_in_projection_ty,
late_bound_in_term,
|br_name| {
struct_span_code_err!(
tcx.dcx(),
binding.span,
E0582,
"binding for associated type `{}` references {}, \
which does not appear in the trait input types",
binding.ident,
br_name
)
},
);
}
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
bounds.push_projection_bound(
tcx,
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty,
term: term.node,
}),
projection_ty
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
binding.span,
);
}
ConvertedBindingKind::Constraint(ast_bounds) => {
hir::TypeBindingKind::Constraint { bounds: ast_bounds } => {
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
//
// `<T as Iterator>::Item: Debug`

View file

@ -1,4 +1,4 @@
use crate::astconv::{AstConv, ConvertedBindingKind};
use crate::astconv::AstConv;
use crate::errors::{
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
@ -111,7 +111,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_kind: ty::AssocKind,
assoc_name: Ident,
span: Span,
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
binding: Option<&hir::TypeBinding<'tcx>>,
) -> ErrorGuaranteed
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
None,
) && suggested_name != assoc_name.name
{
// We suggested constraining a type parameter, but the associated type on it
// We suggested constraining a type parameter, but the associated item on it
// was also not an exact match, so we also suggest changing it.
err.span_suggestion_verbose(
assoc_name.span,
@ -258,16 +258,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
// If we still couldn't find any associated type, and only one associated type exists,
// If we still couldn't find any associated item, and only one associated item exists,
// suggests using it.
if let [candidate_name] = all_candidate_names.as_slice() {
// this should still compile, except on `#![feature(associated_type_defaults)]`
// where it could suggests `type A = Self::A`, thus recursing infinitely
let applicability = if tcx.features().associated_type_defaults {
Applicability::Unspecified
} else {
Applicability::MaybeIncorrect
};
// This should still compile, except on `#![feature(associated_type_defaults)]`
// where it could suggests `type A = Self::A`, thus recursing infinitely.
let applicability =
if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults {
Applicability::Unspecified
} else {
Applicability::MaybeIncorrect
};
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
span: assoc_name.span,
@ -289,13 +290,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_kind: ty::AssocKind,
ident: Ident,
span: Span,
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
binding: Option<&hir::TypeBinding<'tcx>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
&& let Some(binding) = binding
&& let ConvertedBindingKind::Constraint(_) = binding.kind
&& let hir::TypeBindingKind::Constraint { .. } = binding.kind
{
let lo = if binding.gen_args.span_ext.is_dummy() {
ident.span
@ -309,25 +310,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
let wrap_in_braces_sugg = if let Some(binding) = binding
&& let ConvertedBindingKind::Equality(term) = binding.kind
&& let ty::TermKind::Ty(ty) = term.node.unpack()
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind
&& let ty = self.ast_ty_to_ty(hir_ty)
&& (ty.is_enum() || ty.references_error())
&& tcx.features().associated_const_equality
{
Some(errors::AssocKindMismatchWrapInBracesSugg {
lo: term.span.shrink_to_lo(),
hi: term.span.shrink_to_hi(),
lo: hir_ty.span.shrink_to_lo(),
hi: hir_ty.span.shrink_to_hi(),
})
} else {
None
};
// For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
// one can argue that that's more “untuitive” to the user.
// one can argue that that's more “intuitive” to the user.
let (span, expected_because_label, expected, got) = if let Some(binding) = binding
&& let ConvertedBindingKind::Equality(term) = binding.kind
&& let hir::TypeBindingKind::Equality { term } = binding.kind
{
(term.span, Some(ident.span), assoc_item.kind, assoc_kind)
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => tcx.def_span(ct.def_id),
};
(span, Some(ident.span), assoc_item.kind, assoc_kind)
} else {
(ident.span, None, assoc_kind, assoc_item.kind)
};

View file

@ -35,7 +35,6 @@ use rustc_middle::ty::{
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_target::spec::abi;
@ -151,21 +150,6 @@ pub trait AstConv<'tcx> {
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
}
#[derive(Debug)]
struct ConvertedBinding<'a, 'tcx> {
hir_id: hir::HirId,
item_name: Ident,
kind: ConvertedBindingKind<'a, 'tcx>,
gen_args: &'tcx GenericArgs<'tcx>,
span: Span,
}
#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
Equality(Spanned<ty::Term<'tcx>>),
Constraint(&'a [hir::GenericBound<'tcx>]),
}
/// New-typed boolean indicating whether explicit late-bound lifetimes
/// are present in a set of generic arguments.
///
@ -316,7 +300,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Given the type/lifetime/const arguments provided to some path (along with
/// an implicit `Self`, if this is a trait reference), returns the complete
/// set of generic arguments. This may involve applying defaulted type parameters.
/// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`.
///
/// Constraints on associated types are not converted here but
/// separately in `add_predicates_for_ast_type_binding`.
///
/// Example:
///
@ -329,8 +315,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// 2. The path in question is the path to the trait `std::ops::Index`,
/// which will have been resolved to a `def_id`
/// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
/// parameters are returned in the `GenericArgsRef`, the associated type bindings like
/// `Output = u32` are returned from `create_assoc_bindings_for_generic_args`.
/// parameters are returned in the `GenericArgsRef`
/// 4. Associated type bindings like `Output = u32` are contained in `generic_args.bindings`.
///
/// Note that the type listing given here is *exactly* what the user provided.
///
@ -591,52 +577,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(args, arg_count)
}
fn create_assoc_bindings_for_generic_args<'a>(
&self,
generic_args: &'a hir::GenericArgs<'tcx>,
) -> Vec<ConvertedBinding<'a, 'tcx>> {
// Convert associated-type bindings or constraints into a separate vector.
// Example: Given this:
//
// T: Iterator<Item = u32>
//
// The `T` is passed in as a self-type; the `Item = u32` is
// not a "type parameter" of the `Iterator` trait, but rather
// a restriction on `<T as Iterator>::Item`, so it is passed
// back separately.
let assoc_bindings = generic_args
.bindings
.iter()
.map(|binding| {
let kind = match &binding.kind {
hir::TypeBindingKind::Equality { term } => match term {
hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan(
ty.span,
self.ast_ty_to_ty(ty).into(),
)),
hir::Term::Const(c) => {
let span = self.tcx().def_span(c.def_id);
let c = Const::from_anon_const(self.tcx(), c.def_id);
ConvertedBindingKind::Equality(respan(span, c.into()))
}
},
hir::TypeBindingKind::Constraint { bounds } => {
ConvertedBindingKind::Constraint(bounds)
}
};
ConvertedBinding {
hir_id: binding.hir_id,
item_name: binding.ident,
kind,
gen_args: binding.gen_args,
span: binding.span,
}
})
.collect();
assoc_bindings
}
pub fn create_args_for_associated_item(
&self,
span: Span,
@ -742,18 +682,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
debug!(?bound_vars);
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
let poly_trait_ref = ty::Binder::bind_with_vars(
ty::TraitRef::new(tcx, trait_def_id, generic_args),
bound_vars,
);
debug!(?poly_trait_ref, ?assoc_bindings);
debug!(?poly_trait_ref);
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
let mut dup_bindings = FxIndexMap::default();
for binding in &assoc_bindings {
for binding in args.bindings {
// Don't register additional associated type bounds for negative bounds,
// since we should have emitten an error for them earlier, and they will
// not be well-formed!
@ -1029,7 +967,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_kind: ty::AssocKind,
assoc_name: Ident,
span: Span,
binding: Option<&ConvertedBinding<'_, 'tcx>>,
binding: Option<&hir::TypeBinding<'tcx>>,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@ -1069,7 +1007,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Provide a more specific error code index entry for equality bindings.
err.code(
if let Some(binding) = binding
&& let ConvertedBindingKind::Equality(_) = binding.kind
&& let hir::TypeBindingKind::Equality { .. } = binding.kind
{
E0222
} else {
@ -1094,16 +1032,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
if let Some(binding) = binding {
match binding.kind {
ConvertedBindingKind::Equality(term) => {
hir::TypeBindingKind::Equality { term } => {
let term: ty::Term<'_> = match term {
hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
hir::Term::Const(ct) => {
ty::Const::from_anon_const(tcx, ct.def_id).into()
}
};
// FIXME(#97583): This isn't syntactically well-formed!
where_bounds.push(format!(
" T: {trait}::{assoc_name} = {term}",
trait = bound.print_only_trait_path(),
term = term.node,
));
}
// FIXME: Provide a suggestion.
ConvertedBindingKind::Constraint(_bounds) => {}
hir::TypeBindingKind::Constraint { bounds: _ } => {}
}
} else {
err.span_suggestion_verbose(

View file

@ -129,17 +129,20 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
let field_ty = tcx.type_of(field.did).instantiate_identity();
if let Some(adt) = field_ty.ty_adt_def()
&& !adt.is_anonymous()
&& !adt.repr().c()
&& !adt.is_enum()
{
let field_ty_span = tcx.def_span(adt.did());
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
span: tcx.def_span(field.did),
field_ty_span,
field_ty,
field_adt_kind: adt.descr(),
sugg_span: field_ty_span.shrink_to_lo(),
});
if !adt.is_anonymous() && !adt.repr().c() {
let field_ty_span = tcx.def_span(adt.did());
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
span: tcx.def_span(field.did),
field_ty_span,
field_ty,
field_adt_kind: adt.descr(),
sugg_span: field_ty_span.shrink_to_lo(),
});
}
} else {
tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) });
}
}
}

View file

@ -943,7 +943,15 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
}
}
hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
// If this is a direct path to an ADT, we can check it
// If this is a type alias or non-ADT, `check_unnamed_fields` should verify it
if let Some(def_id) = res.opt_def_id()
&& let Some(local) = def_id.as_local()
&& let Node::Item(item) = self.tcx.hir_node_by_def_id(local)
&& item.is_adt()
{
self.check_field_in_nested_adt(self.tcx.adt_def(def_id), field.span);
}
}
// Abort due to errors (there must be an error if an unnamed field
// has any type kind other than an anonymous adt or a named adt)

View file

@ -661,6 +661,13 @@ pub(crate) struct InvalidUnionField {
pub note: (),
}
#[derive(Diagnostic)]
#[diag(hir_analysis_invalid_unnamed_field_ty)]
pub struct InvalidUnnamedFieldTy {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_return_type_notation_on_non_rpitit)]
pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {