Auto merge of #135272 - BoxyUwU:generic_arg_infer_reliability_2, r=compiler-errors

Forbid usage of `hir` `Infer` const/ty variants in ambiguous contexts

The feature `generic_arg_infer` allows providing `_` as an argument to const generics in order to infer them. This introduces a syntactic ambiguity as to whether generic arguments are type or const arguments. In order to get around this we introduced a fourth `GenericArg` variant, `Infer` used to represent `_` as an argument to generic parameters when we don't know if its a type or a const argument.

This made hir visitors that care about `TyKind::Infer` or `ConstArgKind::Infer` very error prone as checking for `TyKind::Infer`s in  `visit_ty` would find *some* type infer arguments but not *all* of them as they would sometimes be lowered to `GenericArg::Infer` instead.

Additionally the `visit_infer` method would previously only visit `GenericArg::Infer` not *all* infers (e.g. `TyKind::Infer`), this made it very easy to override `visit_infer` and expect it to visit all infers when in reality it would only visit *some* infers.

---

This PR aims to fix those issues by making the `TyKind` and `ConstArgKind` types generic over whether the infer types/consts are represented by `Ty/ConstArgKind::Infer` or out of line (e.g. by a `GenericArg::Infer` or accessible by overiding `visit_infer`). We then make HIR Visitors convert all const args and types to the versions where infer vars are stored out of line and call `visit_infer` in cases where a `Ty`/`Const` would previously have had a `Ty/ConstArgKind::Infer` variant:

API Summary
```rust
enum AmbigArg {}

enum Ty/ConstArgKind<Unambig = ()> {
   ...
   Infer(Unambig),
}

impl Ty/ConstArg {
  fn try_as_ambig_ty/ct(self) -> Option<Ty/ConstArg<AmbigArg>>;
}
impl Ty/ConstArg<AmbigArg> {
  fn as_unambig_ty/ct(self) -> Ty/ConstArg;
}

enum InferKind {
  Ty(Ty),
  Const(ConstArg),
  Ambig(InferArg),
}

trait Visitor {
  ...
  fn visit_ty/const_arg(&mut self, Ty/ConstArg<AmbigArg>) -> Self::Result;
  fn visit_infer(&mut self, id: HirId, sp: Span, kind: InferKind) -> Self::Result;
}

// blanket impl'd, not meant to be overriden
trait VisitorExt {
  fn visit_ty/const_arg_unambig(&mut self, Ty/ConstArg) -> Self::Result;
}

fn walk_unambig_ty/const_arg(&mut V, Ty/ConstArg) -> Self::Result;
fn walk_ty/const_arg(&mut V, Ty/ConstArg<AmbigArg>) -> Self::Result;
```

The end result is that `visit_infer` visits *all* infer args and is also the *only* way to visit an infer arg, `visit_ty` and `visit_const_arg` can now no longer encounter a `Ty/ConstArgKind::Infer`. Representing this in the type system means that it is now very difficult to mess things up, either accessing `TyKind::Infer` "just works" and you won't miss *some* type infers- or it doesn't work and you have to look at `visit_infer` or some `GenericArg::Infer` which forces you to think about the full complexity involved.

Unfortunately there is no lint right now about explicitly matching on uninhabited variants, I can't find the context for why this is the case 🤷‍♀️

I'm not convinced the framing of un/ambig ty/consts is necessarily the right one but I'm not sure what would be better. I somewhat like calling them full/partial types based on the fact that `Ty<Partial>`/`Ty<Full>` directly specifies how many of the type kinds are actually represented compared to `Ty<Ambig>` which which leaves that to the reader to figure out based on the logical consequences of it the type being in an ambiguous position.

---

tool changes have been modified in their own commits for easier reviewing by anyone getting cc'd from subtree changes. I also attempted to split out "bug fixes arising from the refactoring" into their own commit so they arent lumped in with a big general refactor commit

Fixes #112110
This commit is contained in:
bors 2025-01-24 11:12:01 +00:00
commit 8231e8599e
119 changed files with 1056 additions and 669 deletions

View file

@ -4,12 +4,12 @@ use clippy_utils::ty::expr_sig;
use clippy_utils::{is_default_equivalent, path_def_id};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
use rustc_span::{Span, sym};
declare_clippy_lint! {
/// ### What it does
@ -92,8 +92,13 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
struct InferVisitor(bool);
impl Visitor<'_> for InferVisitor {
fn visit_ty(&mut self, t: &Ty<'_>) {
self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
fn visit_infer(&mut self, inf_id: HirId, _inf_span: Span, _kind: InferKind<'_>) -> Self::Result {
self.0 = true;
self.visit_id(inf_id);
}
fn visit_ty(&mut self, t: &Ty<'_, AmbigArg>) {
self.0 |= matches!(t.kind, TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
if !self.0 {
walk_ty(self, t);
}
@ -104,7 +109,7 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match cx.tcx.parent_hir_node(expr.hir_id) {
Node::LetStmt(LetStmt { ty: Some(ty), .. }) => {
let mut v = InferVisitor::default();
v.visit_ty(ty);
v.visit_ty_unambig(ty);
!v.0
},
Node::Expr(Expr {

View file

@ -4,7 +4,7 @@ use rustc_middle::ty::Ty;
pub fn check<'tcx>(cx: &LateContext<'tcx>, ty_into: Ty<'_>, cast_to_hir: &'tcx rustc_hir::Ty<'tcx>) {
if let rustc_hir::TyKind::Ptr(rustc_hir::MutTy { ty, .. }) = cast_to_hir.kind
&& matches!(ty.kind, rustc_hir::TyKind::Infer)
&& matches!(ty.kind, rustc_hir::TyKind::Infer(()))
{
clippy_utils::diagnostics::span_lint_and_sugg(
cx,

View file

@ -7,7 +7,7 @@ use rustc_middle::ty;
use super::AS_UNDERSCORE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) {
if matches!(ty.kind, TyKind::Infer) {
if matches!(ty.kind, TyKind::Infer(())) {
span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
let ty_resolved = cx.typeck_results().expr_ty(expr);
if let ty::Error(_) = ty_resolved.kind() {

View file

@ -38,7 +38,7 @@ pub(super) fn check(
return;
};
match cast_to_hir.kind {
TyKind::Infer => {
TyKind::Infer(()) => {
diag.span_suggestion_verbose(
expr.span,
"use `Into::into` instead",

View file

@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
&& let Some(generic_args) = method_path.args
&& let [GenericArg::Type(cast_to)] = generic_args.args
// There probably is no obvious reason to do this, just to be consistent with `as` cases.
&& !is_hir_ty_cfg_dependant(cx, cast_to)
&& !is_hir_ty_cfg_dependant(cx, cast_to.as_unambig_ty())
{
let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);

View file

@ -43,9 +43,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
{
let mut app = Applicability::MachineApplicable;
let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => String::new(),
TyKind::Infer(()) => String::new(),
TyKind::Ptr(mut_ty) => {
if matches!(mut_ty.ty.kind, TyKind::Infer) {
if matches!(mut_ty.ty.kind, TyKind::Infer(())) {
String::new()
} else {
format!(

View file

@ -34,9 +34,9 @@ pub(super) fn check<'tcx>(
let mut app = Applicability::MachineApplicable;
let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => String::new(),
TyKind::Infer(()) => String::new(),
TyKind::Ptr(mut_ty) => {
if matches!(mut_ty.ty.kind, TyKind::Infer) {
if matches!(mut_ty.ty.kind, TyKind::Infer(())) {
String::new()
} else {
format!(

View file

@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
}
},
// Ignore `p as *const _`
TyKind::Infer => return false,
TyKind::Infer(()) => return false,
_ => {},
}

View file

@ -18,7 +18,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>
Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
};
let sugg = if let TyKind::Infer = mut_ty.ty.kind {
let sugg = if let TyKind::Infer(()) = mut_ty.ty.kind {
format!("{std_or_core}::{sugg_fn}()")
} else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) {
format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")

View file

@ -11,10 +11,10 @@ use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
use rustc_hir::{
self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
PatKind, Path, QPath, TyKind, UnOp,
self as hir, AmbigArg, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node,
Pat, PatKind, Path, QPath, TyKind, UnOp,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@ -796,7 +796,7 @@ impl TyCoercionStability {
if let Some(args) = path.args
&& args.args.iter().any(|arg| match arg {
hir::GenericArg::Infer(_) => true,
hir::GenericArg::Type(ty) => ty_contains_infer(ty),
hir::GenericArg::Type(ty) => ty_contains_infer(ty.as_unambig_ty()),
_ => false,
})
{
@ -815,7 +815,7 @@ impl TyCoercionStability {
| TyKind::Path(_) => Self::Deref,
TyKind::OpaqueDef(..)
| TyKind::TraitAscription(..)
| TyKind::Infer
| TyKind::Infer(())
| TyKind::Typeof(..)
| TyKind::TraitObject(..)
| TyKind::InferDelegation(..)
@ -889,29 +889,23 @@ impl TyCoercionStability {
fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
struct V(bool);
impl Visitor<'_> for V {
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
if self.0
|| matches!(
ty.kind,
TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err(_)
)
{
fn visit_infer(&mut self, inf_id: HirId, _inf_span: Span, kind: InferKind<'_>) -> Self::Result {
if let InferKind::Ty(_) | InferKind::Ambig(_) = kind {
self.0 = true;
}
self.visit_id(inf_id);
}
fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
if self.0 || matches!(ty.kind, TyKind::OpaqueDef(..) | TyKind::Typeof(_) | TyKind::Err(_)) {
self.0 = true;
} else {
walk_ty(self, ty);
}
}
fn visit_generic_arg(&mut self, arg: &hir::GenericArg<'_>) {
if self.0 || matches!(arg, hir::GenericArg::Infer(_)) {
self.0 = true;
} else if let hir::GenericArg::Type(ty) = arg {
self.visit_ty(ty);
}
}
}
let mut v = V(false);
v.visit_ty(ty);
v.visit_ty_unambig(ty);
v.0
}

View file

@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Diag;
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{
Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
@ -140,7 +140,7 @@ impl LateLintPass<'_> for DisallowedMacros {
self.check(cx, stmt.span, None);
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_, AmbigArg>) {
self.check(cx, ty.span, None);
}

View file

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
}
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
if let TyKind::Path(path) = &ty.kind {
self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span);
}

View file

@ -76,22 +76,22 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let ExprKind::MethodCall(_method, receiver, args, _) = expr.kind {
for arg in args {
check_clousure(cx, Some(receiver), arg);
check_closure(cx, Some(receiver), arg);
}
}
if let ExprKind::Call(func, args) = expr.kind {
check_clousure(cx, None, func);
check_closure(cx, None, func);
for arg in args {
check_clousure(cx, None, arg);
check_closure(cx, None, arg);
}
}
}
}
#[allow(clippy::too_many_lines)]
fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
let body = if let ExprKind::Closure(c) = expr.kind
&& c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
&& c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(())))
&& matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
&& !expr.span.from_expansion()
{

View file

@ -3,10 +3,10 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::{is_from_proc_macro, trait_ref_of_method};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty};
use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty, walk_unambig_ty};
use rustc_hir::{
BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
PredicateOrigin, Ty, WherePredicate, WherePredicateKind,
AmbigArg, BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item,
ItemKind, PredicateOrigin, Ty, WherePredicate, WherePredicateKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter;
@ -196,7 +196,7 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
self.ty_params.remove(&def_id);
} else {
@ -234,7 +234,7 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
// type, any params we find nested inside of it are being used as concrete types,
// and can therefore can be considered used. So, we're fine to walk the left-hand
// side of the where bound.
walk_ty(self, predicate.bounded_ty);
walk_unambig_ty(self, predicate.bounded_ty);
}
for bound in predicate.bounds {
walk_param_bound(self, bound);

View file

@ -103,7 +103,9 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
"replace the `Into` implementation with `From<{}>`",
middle_trait_ref.self_ty()
);
if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
if let Some(suggestions) =
convert_to_from(cx, into_trait_seg, target_ty.as_unambig_ty(), self_ty, impl_item_ref)
{
diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
} else {
diag.help(message);

View file

@ -2,9 +2,8 @@ use std::borrow::Cow;
use std::collections::BTreeMap;
use rustc_errors::{Applicability, Diag};
use rustc_hir as hir;
use rustc_hir::intravisit::{Visitor, walk_body, walk_expr, walk_inf, walk_ty};
use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_body, walk_expr, walk_ty};
use rustc_hir::{self as hir, AmbigArg, Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
match item.kind {
ItemKind::Impl(impl_) => {
let mut vis = ImplicitHasherTypeVisitor::new(cx);
vis.visit_ty(impl_.self_ty);
vis.visit_ty_unambig(impl_.self_ty);
for target in &vis.found {
if !item.span.eq_ctxt(target.span()) {
@ -159,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
for ty in sig.decl.inputs {
let mut vis = ImplicitHasherTypeVisitor::new(cx);
vis.visit_ty(ty);
vis.visit_ty_unambig(ty);
for target in &vis.found {
if generics.span.from_expansion() {
@ -287,21 +286,13 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
}
impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
if let Some(target) = ImplicitHasherType::new(self.cx, t) {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'_, AmbigArg>) {
if let Some(target) = ImplicitHasherType::new(self.cx, t.as_unambig_ty()) {
self.found.push(target);
}
walk_ty(self, t);
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
if let Some(target) = ImplicitHasherType::new(self.cx, &inf.to_ty()) {
self.found.push(target);
}
walk_inf(self, inf);
}
}
/// Looks for default-hasher-dependent constructors like `HashMap::new`.

View file

@ -3,8 +3,8 @@ use clippy_utils::source::snippet;
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::def_id::DefId;
use rustc_hir::{
AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind,
WherePredicateKind,
AmbigArg, AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers,
TyKind, WherePredicateKind,
};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
@ -146,7 +146,9 @@ fn try_resolve_type<'tcx>(
index: usize,
) -> Option<Ty<'tcx>> {
match args.get(index - 1) {
Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty)),
// I don't think we care about `GenericArg::Infer` since this is all for stuff in type signatures
// which do not permit inference variables.
Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty.as_unambig_ty())),
Some(_) => None,
None => Some(tcx.type_of(generics.own_params[index].def_id).skip_binder()),
}
@ -335,7 +337,7 @@ impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls {
}
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx, AmbigArg>) {
if let TyKind::OpaqueDef(opaque_ty, ..) = ty.kind {
check(cx, opaque_ty.bounds);
}

View file

@ -28,7 +28,7 @@ declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
if let Some(ty) = local.ty // Ensure that it has a type defined
&& let TyKind::Infer = &ty.kind // that type is '_'
&& let TyKind::Infer(()) = &ty.kind // that type is '_'
&& local.span.eq_ctxt(ty.span)
&& !in_external_macro(cx.tcx.sess, local.span)
&& !is_from_proc_macro(cx, ty)

View file

@ -7,13 +7,13 @@ use rustc_errors::Applicability;
use rustc_hir::FnRetTy::Return;
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
use rustc_hir::intravisit::{
Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, walk_poly_trait_ref,
walk_trait_ref, walk_ty, walk_where_predicate,
Visitor, VisitorExt, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound,
walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_unambig_ty, walk_where_predicate,
};
use rustc_hir::{
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node,
PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
WherePredicateKind, lang_items,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -232,11 +232,11 @@ fn could_use_elision<'tcx>(
// extract lifetimes in input argument types
for arg in func.inputs {
input_visitor.visit_ty(arg);
input_visitor.visit_ty_unambig(arg);
}
// extract lifetimes in output type
if let Return(ty) = func.output {
output_visitor.visit_ty(ty);
output_visitor.visit_ty_unambig(ty);
}
for lt in named_generics {
input_visitor.visit_generic_param(lt);
@ -340,7 +340,7 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
&& let Some(self_ty) = func.inputs.first()
{
let mut visitor = RefVisitor::new(cx);
visitor.visit_ty(self_ty);
visitor.visit_ty_unambig(self_ty);
!visitor.all_lts().is_empty()
} else {
@ -426,14 +426,14 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
}
}
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
fn visit_ty(&mut self, ty: &'tcx Ty<'_, AmbigArg>) {
match ty.kind {
TyKind::BareFn(&BareFnTy { decl, .. }) => {
let mut sub_visitor = RefVisitor::new(self.cx);
sub_visitor.visit_fn_decl(decl);
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
},
TyKind::TraitObject(bounds, lt, _) => {
TyKind::TraitObject(bounds, lt) => {
if !lt.is_elided() {
self.unelided_trait_object_lifetime = true;
}
@ -456,7 +456,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
// a predicate like F: Trait or F: for<'a> Trait<'a>
let mut visitor = RefVisitor::new(cx);
// walk the type F, it may not contain LT refs
walk_ty(&mut visitor, pred.bounded_ty);
walk_unambig_ty(&mut visitor, pred.bounded_ty);
if !visitor.all_lts().is_empty() {
return true;
}
@ -477,8 +477,8 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
},
WherePredicateKind::EqPredicate(ref pred) => {
let mut visitor = RefVisitor::new(cx);
walk_ty(&mut visitor, pred.lhs_ty);
walk_ty(&mut visitor, pred.rhs_ty);
walk_unambig_ty(&mut visitor, pred.lhs_ty);
walk_unambig_ty(&mut visitor, pred.rhs_ty);
if !visitor.lts.is_empty() {
return true;
}
@ -541,7 +541,7 @@ where
try_visit!(self.visit_id(hir_id));
self.bounded_ty_depth += 1;
try_visit!(self.visit_ty(bounded_ty));
try_visit!(self.visit_ty_unambig(bounded_ty));
self.bounded_ty_depth -= 1;
walk_list!(self, visit_param_bound, bounds);
@ -625,7 +625,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
if let Some(ref trait_ref) = impl_.of_trait {
walk_trait_ref(&mut checker, trait_ref);
}
walk_ty(&mut checker, impl_.self_ty);
walk_unambig_ty(&mut checker, impl_.self_ty);
for item in impl_.items {
walk_impl_item_ref(&mut checker, item);
}

View file

@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
use hir::def::{DefKind, Res};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{self as hir, AmbigArg};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition;
@ -123,7 +123,7 @@ impl LateLintPass<'_> for MacroUseImports {
self.push_unique_macro_pat_ty(cx, pat.span);
}
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_, AmbigArg>) {
if ty.span.from_expansion() {
self.push_unique_macro_pat_ty(cx, ty.span);
}

View file

@ -6,11 +6,11 @@ use clippy_utils::source::snippet_with_context;
use rustc_ast::ast::LitKind;
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::sym;
use rustc_span::{Span, sym};
declare_clippy_lint! {
/// ### What it does
@ -57,13 +57,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
&& let ctxt = expr.span.ctxt()
&& left_expr.span.ctxt() == ctxt
&& right_expr.span.ctxt() == ctxt
&& let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr)
&& let Some((real_ty_span, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr)
&& matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_))
&& let ExprKind::Lit(lit) = &other_expr.kind
&& let LitKind::Int(Pu128(8), _) = lit.node
{
let mut app = Applicability::MachineApplicable;
let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0;
let ty_snip = snippet_with_context(cx, real_ty_span, ctxt, "..", &mut app).0;
let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
span_lint_and_sugg(
@ -85,21 +85,21 @@ fn get_one_size_of_ty<'tcx>(
cx: &LateContext<'tcx>,
expr1: &'tcx Expr<'_>,
expr2: &'tcx Expr<'_>,
) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>, &'tcx Expr<'tcx>)> {
) -> Option<(Span, Ty<'tcx>, &'tcx Expr<'tcx>)> {
match (get_size_of_ty(cx, expr1), get_size_of_ty(cx, expr2)) {
(Some((real_ty, resolved_ty)), None) => Some((real_ty, resolved_ty, expr2)),
(None, Some((real_ty, resolved_ty))) => Some((real_ty, resolved_ty, expr1)),
(Some((real_ty_span, resolved_ty)), None) => Some((real_ty_span, resolved_ty, expr2)),
(None, Some((real_ty_span, resolved_ty))) => Some((real_ty_span, resolved_ty, expr1)),
_ => None,
}
}
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
if let ExprKind::Call(count_func, []) = expr.kind
&& let ExprKind::Path(ref count_func_qpath) = count_func.kind
&& let QPath::Resolved(_, count_func_path) = count_func_qpath
&& let Some(segment_zero) = count_func_path.segments.first()
&& let Some(args) = segment_zero.args
&& let Some(GenericArg::Type(real_ty)) = args.args.first()
&& let Some(real_ty_span) = args.args.first().map(|arg| arg.span())
&& let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id)
{
@ -107,7 +107,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
.node_args(count_func.hir_id)
.types()
.next()
.map(|resolved_ty| (*real_ty, resolved_ty))
.map(|resolved_ty| (real_ty_span, resolved_ty))
} else {
None
}

View file

@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
Node::Param(..) => (),
Node::LetStmt(local) => {
let Some(ty) = local.ty else { return };
if matches!(ty.kind, TyKind::Infer) {
if matches!(ty.kind, TyKind::Infer(())) {
return;
}
},

View file

@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(
fn_decl.output,
FnRetTy::DefaultReturn(_)
| FnRetTy::Return(hir::Ty {
kind: hir::TyKind::Infer,
kind: hir::TyKind::Infer(()),
..
})
) {

View file

@ -1,14 +1,14 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{self as hir, AmbigArg};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use super::UNNECESSARY_LITERAL_UNWRAP;
fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a>> {
fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a, AmbigArg>> {
let args = args?;
if args.len() <= index {
@ -16,10 +16,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
}
match args[index] {
hir::GenericArg::Type(ty) => match ty.kind {
hir::TyKind::Infer => None,
_ => Some(ty),
},
hir::GenericArg::Type(ty) => Some(ty),
_ => None,
}
}

View file

@ -130,7 +130,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
fn find_elem_explicit_type_span(fn_decl: &FnDecl<'_>) -> Option<Span> {
if let [tuple_ty] = fn_decl.inputs
&& let TyKind::Tup([_idx_ty, elem_ty]) = tuple_ty.kind
&& !matches!(elem_ty.kind, TyKind::Err(..) | TyKind::Infer)
&& !matches!(elem_ty.kind, TyKind::Err(..) | TyKind::Infer(()))
{
Some(elem_ty.span)
} else {

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::{span_lint, span_lint_hir};
use clippy_utils::higher;
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_hir::{self as hir, AmbigArg, intravisit};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
@ -34,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
intravisit::walk_block(&mut MutVisitor { cx }, block);
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_, AmbigArg>) {
if let hir::TyKind::Ref(_, mty) = ty.kind
&& mty.mutbl == hir::Mutability::Mut
&& let hir::TyKind::Ref(_, mty) = mty.ty.kind

View file

@ -190,7 +190,8 @@ fn in_impl<'tcx>(
&& let Some(generic_args) = seg.args
&& let Some(GenericArg::Type(other_ty)) = generic_args.args.last()
{
Some((item.self_ty, other_ty))
// `_` is not permitted in impl headers
Some((item.self_ty, other_ty.as_unambig_ty()))
} else {
None
}

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::last_path_segment;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind};
use rustc_hir::{AmbigArg, GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
@ -36,7 +36,7 @@ declare_clippy_lint! {
declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);
impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
if let TyKind::Ref(_, ref mut_ty) = ty.kind
&& mut_ty.mutbl == Mutability::Not
&& let TyKind::Path(qpath) = &mut_ty.ty.kind

View file

@ -10,8 +10,8 @@ use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{
BoundPolarity, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicateKind,
AmbigArg, BoundPolarity, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment,
PredicateOrigin, QPath, TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicateKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
}
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
if let TyKind::Ref(.., mut_ty) = &ty.kind
&& let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind
&& bounds.len() > 2

View file

@ -52,7 +52,6 @@ pub(super) fn check<'tcx>(
let missing_generic = match args {
Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| match arg {
GenericArg::Infer(_) => true,
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Infer),
_ => false,
}),
_ => true,
@ -65,7 +64,7 @@ pub(super) fn check<'tcx>(
// ... which does have type annotations.
if let Some(ty) = local.ty
// If this is a `let x: _ =`, we should lint.
&& !matches!(ty.kind, TyKind::Infer)
&& !matches!(ty.kind, TyKind::Infer(()))
{
return false;
}

View file

@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
_ => None,
})
{
if is_any_trait(cx, inner) {
if is_any_trait(cx, inner.as_unambig_ty()) {
// Ignore `Box<Any>` types; see issue #1884 for details.
return false;
}
@ -47,7 +47,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
// Originally reported as the issue #3128.
let inner_snippet = snippet(cx, inner.span, "..");
let suggestion = match &inner.kind {
TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => {
format!("&{ltopt}({inner_snippet})")
},
TyKind::Path(qpath)

View file

@ -560,7 +560,7 @@ impl Types {
_ => None,
})
}) {
self.check_ty(cx, ty, context);
self.check_ty(cx, ty.as_unambig_ty(), context);
}
},
QPath::Resolved(None, p) => {
@ -574,7 +574,7 @@ impl Types {
_ => None,
})
}) {
self.check_ty(cx, ty, context);
self.check_ty(cx, ty.as_unambig_ty(), context);
}
},
QPath::TypeRelative(ty, seg) => {
@ -585,7 +585,7 @@ impl Types {
GenericArg::Type(ty) => Some(ty),
_ => None,
}) {
self.check_ty(cx, ty, context);
self.check_ty(cx, ty.as_unambig_ty(), context);
}
}
},

View file

@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint;
use rustc_hir as hir;
use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty};
use rustc_hir::{GenericParamKind, TyKind};
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, TyKind};
use rustc_lint::LateContext;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use super::TYPE_COMPLEXITY;
@ -10,7 +10,7 @@ use super::TYPE_COMPLEXITY;
pub(super) fn check(cx: &LateContext<'_>, ty: &hir::Ty<'_>, type_complexity_threshold: u64) -> bool {
let score = {
let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
visitor.score
};
@ -36,15 +36,15 @@ struct TypeComplexityVisitor {
}
impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
fn visit_infer(&mut self, inf_id: hir::HirId, _inf_span: Span, _kind: InferKind<'tcx>) -> Self::Result {
self.score += 1;
walk_inf(self, inf);
self.visit_id(inf_id);
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_, AmbigArg>) {
let (add_score, sub_nest) = match ty.kind {
// _, &x and *x have only small overhead; don't mess with nesting level
TyKind::Infer | TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0),
// &x and *x have only small overhead; don't mess with nesting level
TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0),
// the "normal" components of a type: named types, arrays/tuples
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
@ -52,7 +52,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
// function types bring a lot of overhead
TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
TyKind::TraitObject(param_bounds, _, _) => {
TyKind::TraitObject(param_bounds, _) => {
let has_lifetime_parameters = param_bounds.iter().any(|bound| {
bound
.bound_generic_params

View file

@ -35,7 +35,8 @@ pub(super) fn check<'tcx>(
&& let Some(GenericArg::Type(boxed_ty)) = last.args.first()
// extract allocator from the Box for later
&& let boxed_alloc_ty = last.args.get(1)
&& let ty_ty = lower_ty(cx.tcx, boxed_ty)
// we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
&& let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
&& !ty_ty.has_escaping_bound_vars()
&& ty_ty.is_sized(cx.tcx, cx.typing_env())
&& let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
@ -55,7 +56,8 @@ pub(super) fn check<'tcx>(
}
},
(Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
lower_ty(cx.tcx, l) == lower_ty(cx.tcx, r),
// we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
_ => false
}
{

View file

@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
return;
}
if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer))
if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer(())))
|| matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
&& expr_needs_inferred_result(cx, init)
{
@ -158,7 +158,7 @@ fn expr_needs_inferred_result<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -
}
while let Some(id) = locals_to_check.pop() {
if let Node::LetStmt(l) = cx.tcx.parent_hir_node(id) {
if !l.ty.is_none_or(|ty| matches!(ty.kind, TyKind::Infer)) {
if !l.ty.is_none_or(|ty| matches!(ty.kind, TyKind::Infer(()))) {
return false;
}
if let Some(e) = l.init {

View file

@ -7,10 +7,10 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty};
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
use rustc_hir::{
self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl,
ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
@ -179,7 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
let mut visitor = SkipTyCollector::default();
visitor.visit_ty(impl_hir_ty);
visitor.visit_ty_unambig(impl_hir_ty);
types_to_skip.extend(visitor.types_to_skip);
}
}
@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
}
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx, AmbigArg>) {
if !hir_ty.span.from_expansion()
&& self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
&& let Some(&StackItem::Check {
@ -218,7 +218,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
&& let ty = if in_body > 0 {
cx.typeck_results().node_type(hir_ty.hir_id)
} else {
lower_ty(cx.tcx, hir_ty)
// We don't care about ignoring infer vars here
lower_ty(cx.tcx, hir_ty.as_unambig_ty())
}
&& let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
&& same_type_and_consts(ty, impl_ty)
@ -275,12 +276,14 @@ struct SkipTyCollector {
}
impl Visitor<'_> for SkipTyCollector {
fn visit_infer(&mut self, inf: &hir::InferArg) {
self.types_to_skip.push(inf.hir_id);
walk_inf(self, inf);
fn visit_infer(&mut self, inf_id: HirId, _inf_span: Span, kind: InferKind<'_>) -> Self::Result {
// Conservatively assume ambiguously kinded inferred arguments are type arguments
if let InferKind::Ambig(_) | InferKind::Ty(_) = kind {
self.types_to_skip.push(inf_id);
}
self.visit_id(inf_id);
}
fn visit_ty(&mut self, hir_ty: &Ty<'_>) {
fn visit_ty(&mut self, hir_ty: &Ty<'_, AmbigArg>) {
self.types_to_skip.push(hir_ty.hir_id);
walk_ty(self, hir_ty);

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
use rustc_hir::{self as hir, HirId, ItemKind, Node};
use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf as _;
@ -44,10 +44,11 @@ declare_clippy_lint! {
declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]);
impl LateLintPass<'_> for ZeroSizedMapValues {
fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) {
fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx, AmbigArg>) {
if !hir_ty.span.from_expansion()
&& !in_trait_impl(cx, hir_ty.hir_id)
&& let ty = ty_from_hir_ty(cx, hir_ty)
// We don't care about infer vars
&& let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
&& (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
&& let ty::Adt(_, args) = ty.kind()
&& let ty = args.type_at(1)

View file

@ -399,8 +399,8 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
TyKind::Tup([head, .., tail]) => (ty_search_pat(head).0, ty_search_pat(tail).1),
TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
TyKind::Path(qpath) => qpath_search_pat(&qpath),
TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
TyKind::TraitObject(_, _, TraitObjectSyntax::Dyn) => (Pat::Str("dyn"), Pat::Str("")),
TyKind::Infer(()) => (Pat::Str("_"), Pat::Str("_")),
TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => (Pat::Str("dyn"), Pat::Str("")),
// NOTE: `TraitObject` is incomplete. It will always return true then.
_ => (Pat::Str(""), Pat::Str("")),
}

View file

@ -459,9 +459,9 @@ impl HirEqInterExpr<'_, '_, '_> {
fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
match (left, right) {
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l, r),
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l.as_unambig_ct(), r.as_unambig_ct()),
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
(GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
(GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty.as_unambig_ty(), r_ty.as_unambig_ty()),
(GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()),
_ => false,
}
@ -618,7 +618,7 @@ impl HirEqInterExpr<'_, '_, '_> {
},
(TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
(&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
(&TyKind::Infer, &TyKind::Infer) => true,
(&TyKind::Infer(()), &TyKind::Infer(())) => true,
_ => false,
}
}
@ -1281,7 +1281,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}
},
TyKind::Path(qpath) => self.hash_qpath(qpath),
TyKind::TraitObject(_, lifetime, _) => {
TyKind::TraitObject(_, lifetime) => {
self.hash_lifetime(lifetime);
},
TyKind::Typeof(anon_const) => {
@ -1291,7 +1291,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_ty(binder.inner_ty);
},
TyKind::Err(_)
| TyKind::Infer
| TyKind::Infer(())
| TyKind::Never
| TyKind::InferDelegation(..)
| TyKind::OpaqueDef(_)
@ -1318,8 +1318,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
for arg in arg_list {
match *arg {
GenericArg::Lifetime(l) => self.hash_lifetime(l),
GenericArg::Type(ty) => self.hash_ty(ty),
GenericArg::Const(ca) => self.hash_const_arg(ca),
GenericArg::Type(ty) => self.hash_ty(ty.as_unambig_ty()),
GenericArg::Const(ca) => self.hash_const_arg(ca.as_unambig_ct()),
GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
}
}

View file

@ -437,7 +437,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
.map_or(&[][..], |a| a.args)
.iter()
.filter_map(|a| match a {
hir::GenericArg::Type(ty) => Some(*ty),
hir::GenericArg::Type(ty) => Some(ty.as_unambig_ty()),
_ => None,
})
}
@ -2148,7 +2148,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match expr.kind {
ExprKind::Closure(&Closure { body, fn_decl, .. })
if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) =>
if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) =>
{
is_body_identity_function(cx, cx.tcx.hir().body(body))
},

View file

@ -14,8 +14,8 @@
use crate::def_path_res;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{Visitor, walk_qpath, walk_ty};
use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
use rustc_span::{Span, Symbol};
@ -116,14 +116,15 @@ impl<'cx> Visitor<'cx> for CertaintyVisitor<'cx, '_> {
}
}
fn visit_ty(&mut self, ty: &'cx hir::Ty<'_>) {
if matches!(ty.kind, TyKind::Infer) {
self.certainty = Certainty::Uncertain;
}
fn visit_ty(&mut self, ty: &'cx hir::Ty<'_, AmbigArg>) {
if self.certainty != Certainty::Uncertain {
walk_ty(self, ty);
}
}
fn visit_infer(&mut self, _inf_id: HirId, _inf_span: Span, _kind: InferKind<'cx>) -> Self::Result {
self.certainty = Certainty::Uncertain;
}
}
fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
@ -139,7 +140,7 @@ fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
}
let mut visitor = CertaintyVisitor::new(cx);
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
visitor.certainty
}

View file

@ -2,7 +2,7 @@ use crate::ty::needs_ordered_drop;
use crate::{get_enclosing_block, path_to_local_id};
use core::ops::ControlFlow;
use rustc_ast::visit::{VisitorResult, try_visit};
use rustc_hir as hir;
use rustc_hir::{self as hir, AmbigArg};
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr};
use rustc_hir::{
@ -122,7 +122,7 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
}
// Avoid unnecessary `walk_*` calls.
fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
ControlFlow::Continue(())
}
fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
@ -172,7 +172,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
ControlFlow::Continue(())
}
// Avoid unnecessary `walk_*` calls.
fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
ControlFlow::Continue(())
}
fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {