Rename HIR TypeBinding
to AssocItemConstraint
and related cleanup
This commit is contained in:
parent
a456300af5
commit
040edea332
@ -3,7 +3,7 @@
|
|||||||
use rustc_errors::{Applicability, SuggestionStyle};
|
use rustc_errors::{Applicability, SuggestionStyle};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, TypeBinding,
|
GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, AssocItemConstraint,
|
||||||
WherePredicate,
|
WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_hir_analysis::lower_ty;
|
use rustc_hir_analysis::lower_ty;
|
||||||
@ -54,9 +54,9 @@ fn emit_lint(
|
|||||||
poly_trait: &rustc_hir::PolyTraitRef<'_>,
|
poly_trait: &rustc_hir::PolyTraitRef<'_>,
|
||||||
bounds: GenericBounds<'_>,
|
bounds: GenericBounds<'_>,
|
||||||
index: usize,
|
index: usize,
|
||||||
// The bindings that were implied, used for suggestion purposes since removing a bound with associated types
|
// The constraints that were implied, used for suggestion purposes since removing a bound with
|
||||||
// means we might need to then move it to a different bound
|
// associated types means we might need to then move it to a different bound.
|
||||||
implied_bindings: &[TypeBinding<'_>],
|
implied_constraints: &[AssocItemConstraint<'_>],
|
||||||
bound: &ImplTraitBound<'_>,
|
bound: &ImplTraitBound<'_>,
|
||||||
) {
|
) {
|
||||||
let implied_by = snippet(cx, bound.span, "..");
|
let implied_by = snippet(cx, bound.span, "..");
|
||||||
@ -83,29 +83,29 @@ fn emit_lint(
|
|||||||
|
|
||||||
let mut sugg = vec![(implied_span_extended, String::new())];
|
let mut sugg = vec![(implied_span_extended, String::new())];
|
||||||
|
|
||||||
// We also might need to include associated type binding that were specified in the implied bound,
|
// We also might need to include associated item constraints that were specified in the implied bound,
|
||||||
// but omitted in the implied-by bound:
|
// but omitted in the implied-by bound:
|
||||||
// `fn f() -> impl Deref<Target = u8> + DerefMut`
|
// `fn f() -> impl Deref<Target = u8> + DerefMut`
|
||||||
// If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
|
// If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
|
||||||
let omitted_assoc_tys: Vec<_> = implied_bindings
|
let omitted_constraints: Vec<_> = implied_constraints
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|binding| !bound.bindings.iter().any(|b| b.ident == binding.ident))
|
.filter(|constraint| !bound.constraints.iter().any(|c| c.ident == constraint.ident))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !omitted_assoc_tys.is_empty() {
|
if !omitted_constraints.is_empty() {
|
||||||
// `<>` needs to be added if there aren't yet any generic arguments or bindings
|
// `<>` needs to be added if there aren't yet any generic arguments or constraints
|
||||||
let needs_angle_brackets = bound.args.is_empty() && bound.bindings.is_empty();
|
let needs_angle_brackets = bound.args.is_empty() && bound.constraints.is_empty();
|
||||||
let insert_span = match (bound.args, bound.bindings) {
|
let insert_span = match (bound.args, bound.constraints) {
|
||||||
([.., arg], [.., binding]) => arg.span().max(binding.span).shrink_to_hi(),
|
([.., arg], [.., constraint]) => arg.span().max(constraint.span).shrink_to_hi(),
|
||||||
([.., arg], []) => arg.span().shrink_to_hi(),
|
([.., arg], []) => arg.span().shrink_to_hi(),
|
||||||
([], [.., binding]) => binding.span.shrink_to_hi(),
|
([], [.., constraint]) => constraint.span.shrink_to_hi(),
|
||||||
([], []) => bound.span.shrink_to_hi(),
|
([], []) => bound.span.shrink_to_hi(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut associated_tys_sugg = if needs_angle_brackets {
|
let mut constraints_sugg = if needs_angle_brackets {
|
||||||
"<".to_owned()
|
"<".to_owned()
|
||||||
} else {
|
} else {
|
||||||
// If angle brackets aren't needed (i.e., there are already generic arguments or bindings),
|
// If angle brackets aren't needed (i.e., there are already generic arguments or constraints),
|
||||||
// we need to add a comma:
|
// we need to add a comma:
|
||||||
// `impl A<B, C >`
|
// `impl A<B, C >`
|
||||||
// ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
|
// ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
|
||||||
@ -113,16 +113,16 @@ fn emit_lint(
|
|||||||
", ".to_owned()
|
", ".to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
for (index, binding) in omitted_assoc_tys.into_iter().enumerate() {
|
for (index, constraint) in omitted_constraints.into_iter().enumerate() {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
associated_tys_sugg += ", ";
|
constraints_sugg += ", ";
|
||||||
}
|
}
|
||||||
associated_tys_sugg += &snippet(cx, binding.span, "..");
|
constraints_sugg += &snippet(cx, constraint.span, "..");
|
||||||
}
|
}
|
||||||
if needs_angle_brackets {
|
if needs_angle_brackets {
|
||||||
associated_tys_sugg += ">";
|
constraints_sugg += ">";
|
||||||
}
|
}
|
||||||
sugg.push((insert_span, associated_tys_sugg));
|
sugg.push((insert_span, constraints_sugg));
|
||||||
}
|
}
|
||||||
|
|
||||||
diag.multipart_suggestion_with_style(
|
diag.multipart_suggestion_with_style(
|
||||||
@ -229,8 +229,8 @@ struct ImplTraitBound<'tcx> {
|
|||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
/// The generic arguments on the `impl Trait` bound
|
/// The generic arguments on the `impl Trait` bound
|
||||||
args: &'tcx [GenericArg<'tcx>],
|
args: &'tcx [GenericArg<'tcx>],
|
||||||
/// The associated types on this bound
|
/// The associated item constraints of this bound
|
||||||
bindings: &'tcx [TypeBinding<'tcx>],
|
constraints: &'tcx [AssocItemConstraint<'tcx>],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an `impl Trait` type, gets all the supertraits from each bound ("implied bounds").
|
/// Given an `impl Trait` type, gets all the supertraits from each bound ("implied bounds").
|
||||||
@ -253,7 +253,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
|
|||||||
Some(ImplTraitBound {
|
Some(ImplTraitBound {
|
||||||
predicates,
|
predicates,
|
||||||
args: path.args.map_or([].as_slice(), |p| p.args),
|
args: path.args.map_or([].as_slice(), |p| p.args),
|
||||||
bindings: path.args.map_or([].as_slice(), |p| p.bindings),
|
constraints: path.args.map_or([].as_slice(), |p| p.constraints),
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
span: bound.span(),
|
span: bound.span(),
|
||||||
})
|
})
|
||||||
@ -310,20 +310,20 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
|
|||||||
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
|
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
|
||||||
&& let [.., path] = poly_trait.trait_ref.path.segments
|
&& let [.., path] = poly_trait.trait_ref.path.segments
|
||||||
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
|
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
|
||||||
&& let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings)
|
&& let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints)
|
||||||
&& let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id()
|
&& let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id()
|
||||||
&& let Some(bound) = find_bound_in_supertraits(cx, def_id, implied_args, &supertraits)
|
&& let Some(bound) = find_bound_in_supertraits(cx, def_id, implied_args, &supertraits)
|
||||||
// If the implied bound has a type binding that also exists in the implied-by trait,
|
// If the implied bound has a type binding that also exists in the implied-by trait,
|
||||||
// then we shouldn't lint. See #11880 for an example.
|
// then we shouldn't lint. See #11880 for an example.
|
||||||
&& let assocs = cx.tcx.associated_items(bound.trait_def_id)
|
&& let assocs = cx.tcx.associated_items(bound.trait_def_id)
|
||||||
&& !implied_bindings.iter().any(|binding| {
|
&& !implied_constraints.iter().any(|constraint| {
|
||||||
assocs
|
assocs
|
||||||
.filter_by_name_unhygienic(binding.ident.name)
|
.filter_by_name_unhygienic(constraint.ident.name)
|
||||||
.next()
|
.next()
|
||||||
.is_some_and(|assoc| assoc.kind == ty::AssocKind::Type)
|
.is_some_and(|assoc| assoc.kind == ty::AssocKind::Type)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
emit_lint(cx, poly_trait, bounds, index, implied_bindings, bound);
|
emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
||||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
|
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
|
||||||
TraitItemRef, TyKind, TypeBindingKind,
|
TraitItemRef, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||||
@ -307,17 +307,12 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&
|
|||||||
&& let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds
|
&& let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds
|
||||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||||
&& let Some(generic_args) = segment.args
|
&& let Some(generic_args) = segment.args
|
||||||
&& generic_args.bindings.len() == 1
|
&& let [constraint] = generic_args.constraints
|
||||||
&& let TypeBindingKind::Equality {
|
&& let Some(ty) = constraint.ty()
|
||||||
term:
|
&& let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
|
||||||
rustc_hir::Term::Ty(rustc_hir::Ty {
|
&& let [segment] = path.segments
|
||||||
kind: TyKind::Path(QPath::Resolved(_, path)),
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
} = &generic_args.bindings[0].kind
|
|
||||||
&& path.segments.len() == 1
|
|
||||||
{
|
{
|
||||||
return Some(&path.segments[0]);
|
return Some(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
|
Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
|
||||||
FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
|
FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, TraitRef, Ty, TyKind,
|
||||||
TypeBindingKind,
|
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
@ -138,10 +137,9 @@ fn future_trait_ref<'tcx>(
|
|||||||
fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
|
fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
|
||||||
if let Some(segment) = trait_ref.path.segments.last()
|
if let Some(segment) = trait_ref.path.segments.last()
|
||||||
&& let Some(args) = segment.args
|
&& let Some(args) = segment.args
|
||||||
&& args.bindings.len() == 1
|
&& let [constraint] = args.constraints
|
||||||
&& let binding = &args.bindings[0]
|
&& constraint.ident.name == sym::Output
|
||||||
&& binding.ident.name == sym::Output
|
&& let Some(output) = constraint.ty()
|
||||||
&& let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind
|
|
||||||
{
|
{
|
||||||
return Some(output);
|
return Some(output);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
|
|||||||
pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool {
|
pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool {
|
||||||
match (l, r) {
|
match (l, r) {
|
||||||
(AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r),
|
(AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r),
|
||||||
(AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_constraint(l, r),
|
(AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_item_constraint(l, r),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -802,8 +802,8 @@ fn eq_term(l: &Term, r: &Term) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
|
pub fn eq_assoc_item_constraint(l: &AssocItemConstraint, r: &AssocItemConstraint) -> bool {
|
||||||
use AssocConstraintKind::*;
|
use AssocItemConstraintKind::*;
|
||||||
eq_id(l.ident, r.ident)
|
eq_id(l.ident, r.ident)
|
||||||
&& match (&l.kind, &r.kind) {
|
&& match (&l.kind, &r.kind) {
|
||||||
(Equality { term: l }, Equality { term: r }) => eq_term(l, r),
|
(Equality { term: l }, Equality { term: r }) => eq_term(l, r),
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
|
ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
|
||||||
GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
|
GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
|
||||||
PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
|
PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, AssocItemConstraint,
|
||||||
};
|
};
|
||||||
use rustc_lexer::{tokenize, TokenKind};
|
use rustc_lexer::{tokenize, TokenKind};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
@ -486,7 +486,7 @@ pub fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool {
|
|||||||
fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
|
fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
|
||||||
if left.parenthesized == right.parenthesized {
|
if left.parenthesized == right.parenthesized {
|
||||||
over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
|
over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
|
||||||
&& over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
|
&& over(left.constraints, right.constraints, |l, r| self.eq_assoc_type_binding(l, r))
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -518,8 +518,8 @@ pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
|
fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool {
|
||||||
left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
|
left.ident.name == right.ident.name && self.eq_ty(left.ty().expect("expected assoc type binding"), right.ty().expect("expected assoc type binding"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
|
fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user