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
119 changed files with 1056 additions and 669 deletions
+35 -3
View File
@@ -28,6 +28,7 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::tagged_ptr::Tag;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
pub use rustc_span::AttrId;
use rustc_span::source_map::{Spanned, respan};
@@ -287,6 +288,7 @@ pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
}
}
use crate::AstDeref;
pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId};
/// Modifiers on a trait bound like `~const`, `?` and `!`.
@@ -2165,6 +2167,14 @@ pub fn peel_refs(&self) -> &Self {
}
final_ty
}
pub fn is_maybe_parenthesised_infer(&self) -> bool {
match &self.kind {
TyKind::Infer => true,
TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(),
_ => false,
}
}
}
#[derive(Clone, Encodable, Decodable, Debug)]
@@ -2269,10 +2279,32 @@ pub fn is_simple_path(&self) -> Option<Symbol> {
/// Syntax used to declare a trait object.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[repr(u8)]
pub enum TraitObjectSyntax {
Dyn,
DynStar,
None,
// SAFETY: When adding new variants make sure to update the `Tag` impl.
Dyn = 0,
DynStar = 1,
None = 2,
}
/// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means
/// it can be represented with a `u2`. We use `repr(u8)` to guarantee the
/// discriminants of the variants are no greater than `3`.
unsafe impl Tag for TraitObjectSyntax {
const BITS: u32 = 2;
fn into_usize(self) -> usize {
self as u8 as usize
}
unsafe fn from_usize(tag: usize) -> Self {
match tag {
0 => TraitObjectSyntax::Dyn,
1 => TraitObjectSyntax::DynStar,
2 => TraitObjectSyntax::None,
_ => unreachable!(),
}
}
}
#[derive(Clone, Encodable, Decodable, Debug)]
+26 -14
View File
@@ -1,3 +1,4 @@
use intravisit::InferKind;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
@@ -265,14 +266,6 @@ fn visit_inline_const(&mut self, constant: &'hir ConstBlock) {
});
}
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
self.insert(const_arg.span(), const_arg.hir_id, Node::ConstArg(const_arg));
self.with_parent(const_arg.hir_id, |this| {
intravisit::walk_const_arg(this, const_arg);
});
}
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
@@ -302,22 +295,41 @@ fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) {
intravisit::walk_path_segment(self, path_segment);
}
fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
self.insert(ty.span, ty.hir_id, Node::Ty(ty));
fn visit_ty(&mut self, ty: &'hir Ty<'hir, AmbigArg>) {
self.insert(ty.span, ty.hir_id, Node::Ty(ty.as_unambig_ty()));
self.with_parent(ty.hir_id, |this| {
intravisit::walk_ty(this, ty);
});
}
fn visit_infer(&mut self, inf: &'hir InferArg) {
self.insert(inf.span, inf.hir_id, Node::Infer(inf));
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
self.insert(
const_arg.as_unambig_ct().span(),
const_arg.hir_id,
Node::ConstArg(const_arg.as_unambig_ct()),
);
self.with_parent(inf.hir_id, |this| {
intravisit::walk_inf(this, inf);
self.with_parent(const_arg.hir_id, |this| {
intravisit::walk_ambig_const_arg(this, const_arg);
});
}
fn visit_infer(
&mut self,
inf_id: HirId,
inf_span: Span,
kind: InferKind<'hir>,
) -> Self::Result {
match kind {
InferKind::Ty(ty) => self.insert(inf_span, inf_id, Node::Ty(ty)),
InferKind::Const(ct) => self.insert(inf_span, inf_id, Node::ConstArg(ct)),
InferKind::Ambig(inf) => self.insert(inf_span, inf_id, Node::Infer(inf)),
}
self.visit_id(inf_id);
}
fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
+25 -15
View File
@@ -48,6 +48,7 @@
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
@@ -1083,17 +1084,22 @@ fn lower_generic_arg(
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
ast::GenericArg::Type(ty) => {
// We cannot just match on `TyKind::Infer` as `(_)` is represented as
// `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer`
if ty.is_maybe_parenthesised_infer() {
return GenericArg::Infer(hir::InferArg {
hir_id: self.lower_node_id(ty.id),
span: self.lower_span(ty.span),
});
}
match &ty.kind {
TyKind::Infer if self.tcx.features().generic_arg_infer() => {
return GenericArg::Infer(hir::InferArg {
hir_id: self.lower_node_id(ty.id),
span: self.lower_span(ty.span),
});
}
// We parse const arguments as path types as we cannot distinguish them during
// parsing. We try to resolve that ambiguity by attempting resolution in both the
// type and value namespaces. If we resolved the path in the value namespace, we
// transform it into a generic const argument.
//
// FIXME: Should we be handling `(PATH_TO_CONST)`?
TyKind::Path(None, path) => {
if let Some(res) = self
.resolver
@@ -1110,15 +1116,17 @@ fn lower_generic_arg(
let ct =
self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
return GenericArg::Const(ct);
return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
}
}
}
_ => {}
}
GenericArg::Type(self.lower_ty(ty, itctx))
GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
}
ast::GenericArg::Const(ct) => {
GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
}
ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
}
}
@@ -1158,7 +1166,10 @@ fn lower_path_ty(
let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound)
});
let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
let kind = hir::TyKind::TraitObject(
bounds,
TaggedRef::new(lifetime_bound, TraitObjectSyntax::None),
);
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
}
@@ -1185,7 +1196,7 @@ fn ty_tup(&mut self, span: Span, tys: &'hir [hir::Ty<'hir>]) -> hir::Ty<'hir> {
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Infer => hir::TyKind::Infer(()),
TyKind::Err(guar) => hir::TyKind::Err(*guar),
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
@@ -1309,7 +1320,7 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
(bounds, lifetime_bound)
});
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind))
}
TyKind::ImplTrait(def_node_id, bounds) => {
let span = t.span;
@@ -2041,7 +2052,7 @@ fn lower_array_length_to_const_arg(&mut self, c: &AnonConst) -> &'hir hir::Const
)
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
}
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span));
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
}
_ => self.lower_anon_const_to_const_arg(c),
@@ -2365,8 +2376,7 @@ fn ty_path(&mut self, mut hir_id: HirId, span: Span, qpath: hir::QPath<'hir>) ->
hir_id = self.next_id();
hir::TyKind::TraitObject(
arena_vec![self; principal],
self.elided_dyn_bound(span),
TraitObjectSyntax::None,
TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None),
)
}
_ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),
+3 -1
View File
@@ -525,7 +525,9 @@ fn lower_parenthesized_parameter_data(
}
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
let args = smallvec![GenericArg::Type(
self.arena.alloc(self.ty_tup(*inputs_span, inputs)).try_as_ambig_ty().unwrap()
)];
// If we have a bound like `async Fn() -> T`, make sure that we mark the
// `Output = T` associated type bound with the right feature gates.
@@ -8,7 +8,7 @@
use rustc_hir::WherePredicateKind::BoundPredicate;
use rustc_hir::def::Res::Def;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
use rustc_middle::bug;
@@ -887,7 +887,7 @@ fn add_static_impl_trait_suggestion(
if alias_ty.span.desugaring_kind().is_some() {
// Skip `async` desugaring `impl Future`.
}
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
if lt.ident.name == kw::Empty {
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
} else {
@@ -987,7 +987,7 @@ fn suggest_constrain_dyn_trait_in_impl(
for found_did in found_dids {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(self_ty);
hir_v.visit_ty_unambig(self_ty);
debug!("trait spans found: {:?}", traits);
for span in &traits {
let mut multi_span: MultiSpan = vec![*span].into();
@@ -432,7 +432,7 @@ fn get_argument_hir_ty_for_highlighting(
// must highlight the variable.
// NOTE(eddyb) this is handled in/by the sole caller
// (`give_name_if_anonymous_region_appears_in_arguments`).
hir::TyKind::Infer => None,
hir::TyKind::Infer(()) => None,
_ => Some(argument_hir_ty),
}
@@ -615,7 +615,7 @@ fn try_match_adt_and_generic_args<'hir>(
}
(GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
search_stack.push((ty, hir_ty));
search_stack.push((ty, hir_ty.as_unambig_ty()));
}
(GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
+160 -47
View File
@@ -15,6 +15,7 @@
};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::LocalDefId;
@@ -30,7 +31,7 @@
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::{DefId, LocalDefIdMap};
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::FnKind;
use crate::intravisit::{FnKind, VisitorExt};
#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Lifetime {
@@ -263,14 +264,58 @@ pub fn args(&self) -> &GenericArgs<'hir> {
/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args
/// that are [just paths](ConstArgKind::Path) (currently just bare const params)
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
///
/// The `Unambig` generic parameter represents whether the position this const is from is
/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an
/// ambiguous context the parameter is instantiated with an uninhabited type making the
/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct ConstArg<'hir> {
#[repr(C)]
pub struct ConstArg<'hir, Unambig = ()> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: ConstArgKind<'hir>,
pub kind: ConstArgKind<'hir, Unambig>,
}
impl<'hir> ConstArg<'hir, AmbigArg> {
/// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position.
///
/// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant
/// to be used. Care should be taken to separately handle infer consts when calling this
/// function as it cannot be handled by downstream code making use of the returned const.
///
/// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
/// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
///
/// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
pub fn as_unambig_ct(&self) -> &ConstArg<'hir> {
// SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the
// layout is the same across different ZST type arguments.
let ptr = self as *const ConstArg<'hir, AmbigArg> as *const ConstArg<'hir, ()>;
unsafe { &*ptr }
}
}
impl<'hir> ConstArg<'hir> {
/// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is
/// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions.
///
/// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
/// infer consts are relevant to you then care should be taken to handle them separately.
pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> {
if let ConstArgKind::Infer(_, ()) = self.kind {
return None;
}
// SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the layout is
// the same across different ZST type arguments. We also asserted that the `self` is
// not a `ConstArgKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
let ptr = self as *const ConstArg<'hir> as *const ConstArg<'hir, AmbigArg>;
Some(unsafe { &*ptr })
}
}
impl<'hir, Unambig> ConstArg<'hir, Unambig> {
pub fn anon_const_hir_id(&self) -> Option<HirId> {
match self.kind {
ConstArgKind::Anon(ac) => Some(ac.hir_id),
@@ -282,14 +327,15 @@ pub fn span(&self) -> Span {
match self.kind {
ConstArgKind::Path(path) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
ConstArgKind::Infer(span) => span,
ConstArgKind::Infer(span, _) => span,
}
}
}
/// See [`ConstArg`].
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum ConstArgKind<'hir> {
#[repr(u8, C)]
pub enum ConstArgKind<'hir, Unambig = ()> {
/// **Note:** Currently this is only used for bare const params
/// (`N` where `fn foo<const N: usize>(...)`),
/// not paths to any const (`N` where `const N: usize = ...`).
@@ -297,11 +343,9 @@ pub enum ConstArgKind<'hir> {
/// However, in the future, we'll be using it for all of those.
Path(QPath<'hir>),
Anon(&'hir AnonConst),
/// **Note:** Not all inferred consts are represented as
/// `ConstArgKind::Infer`. In cases where it is ambiguous whether
/// a generic arg is a type or a const, inference variables are
/// represented as `GenericArg::Infer` instead.
Infer(Span),
/// This variant is not always used to represent inference consts, sometimes
/// [`GenericArg::Infer`] is used instead.
Infer(Span, Unambig),
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
@@ -313,19 +357,24 @@ pub struct InferArg {
impl InferArg {
pub fn to_ty(&self) -> Ty<'static> {
Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id }
Ty { kind: TyKind::Infer(()), span: self.span, hir_id: self.hir_id }
}
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
Const(&'hir ConstArg<'hir>),
/// **Note:** Inference variables are only represented as
/// `GenericArg::Infer` in cases where it is ambiguous whether
/// a generic arg is a type or a const. Otherwise, inference variables
/// are represented as `TyKind::Infer` or `ConstArgKind::Infer`.
Type(&'hir Ty<'hir, AmbigArg>),
Const(&'hir ConstArg<'hir, AmbigArg>),
/// Inference variables in [`GenericArg`] are always represnted by
/// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and
/// [`ConstArgKind`] as it is not clear until hir ty lowering whether a
/// `_` argument is a type or const argument.
///
/// However, some builtin types' generic arguments are represented by [`TyKind`]
/// without a [`GenericArg`], instead directly storing a [`Ty`] or [`ConstArg`]. In
/// such cases they *are* represented by the `Infer` variants on [`TyKind`] and
/// [`ConstArgKind`] as it is not ambiguous whether the argument is a type or const.
Infer(InferArg),
}
@@ -353,7 +402,7 @@ pub fn descr(&self) -> &'static str {
GenericArg::Lifetime(_) => "lifetime",
GenericArg::Type(_) => "type",
GenericArg::Const(_) => "constant",
GenericArg::Infer(_) => "inferred",
GenericArg::Infer(_) => "placeholder",
}
}
@@ -764,11 +813,8 @@ pub fn bounds_span_for_suggestions(
&& let [.., segment] = trait_ref.path.segments
&& let Some(ret_ty) = segment.args().paren_sugar_output()
&& let ret_ty = ret_ty.peel_refs()
&& let TyKind::TraitObject(
_,
_,
TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
) = ret_ty.kind
&& let TyKind::TraitObject(_, tagged_ptr) = ret_ty.kind
&& let TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar = tagged_ptr.tag()
&& ret_ty.span.can_be_used_for_suggestions()
{
Some(ret_ty.span)
@@ -2917,15 +2963,84 @@ pub fn descr(&self) -> &'static str {
}
}
/// An uninhabited enum used to make `Infer` variants on [`Ty`] and [`ConstArg`] be
/// unreachable. Zero-Variant enums are guaranteed to have the same layout as the never
/// type.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Ty<'hir> {
pub enum AmbigArg {}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
#[repr(C)]
/// Represents a type in the `HIR`.
///
/// The `Unambig` generic parameter represents whether the position this type is from is
/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an
/// ambiguous context the parameter is instantiated with an uninhabited type making the
/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
pub struct Ty<'hir, Unambig = ()> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: TyKind<'hir>,
pub span: Span,
pub kind: TyKind<'hir, Unambig>,
}
impl<'hir> Ty<'hir, AmbigArg> {
/// Converts a `Ty` in an ambiguous position to one in an unambiguous position.
///
/// Functions accepting an unambiguous types may expect the [`TyKind::Infer`] variant
/// to be used. Care should be taken to separately handle infer types when calling this
/// function as it cannot be handled by downstream code making use of the returned ty.
///
/// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
/// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
///
/// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
pub fn as_unambig_ty(&self) -> &Ty<'hir> {
// SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
// the same across different ZST type arguments.
let ptr = self as *const Ty<'hir, AmbigArg> as *const Ty<'hir, ()>;
unsafe { &*ptr }
}
}
impl<'hir> Ty<'hir> {
/// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is
/// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions.
///
/// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if
/// infer types are relevant to you then care should be taken to handle them separately.
pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> {
if let TyKind::Infer(()) = self.kind {
return None;
}
// SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
// the same across different ZST type arguments. We also asserted that the `self` is
// not a `TyKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
let ptr = self as *const Ty<'hir> as *const Ty<'hir, AmbigArg>;
Some(unsafe { &*ptr })
}
}
impl<'hir> Ty<'hir, AmbigArg> {
pub fn peel_refs(&self) -> &Ty<'hir> {
let mut final_ty = self.as_unambig_ty();
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
}
}
impl<'hir> Ty<'hir> {
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
}
/// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
let TyKind::Path(QPath::Resolved(None, path)) = self.kind else {
@@ -2942,19 +3057,11 @@ pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
}
}
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
}
pub fn find_self_aliases(&self) -> Vec<Span> {
use crate::intravisit::Visitor;
struct MyVisitor(Vec<Span>);
impl<'v> Visitor<'v> for MyVisitor {
fn visit_ty(&mut self, t: &'v Ty<'v>) {
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) {
if matches!(
&t.kind,
TyKind::Path(QPath::Resolved(_, Path {
@@ -2970,7 +3077,7 @@ fn visit_ty(&mut self, t: &'v Ty<'v>) {
}
let mut my_visitor = MyVisitor(vec![]);
my_visitor.visit_ty(self);
my_visitor.visit_ty_unambig(self);
my_visitor.0
}
@@ -2979,14 +3086,14 @@ fn visit_ty(&mut self, t: &'v Ty<'v>) {
pub fn is_suggestable_infer_ty(&self) -> bool {
fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
generic_args.iter().any(|arg| match arg {
GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
GenericArg::Type(ty) => ty.as_unambig_ty().is_suggestable_infer_ty(),
GenericArg::Infer(_) => true,
_ => false,
})
}
debug!(?self);
match &self.kind {
TyKind::Infer => true,
TyKind::Infer(()) => true,
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
TyKind::Array(ty, length) => {
ty.is_suggestable_infer_ty() || matches!(length.kind, ConstArgKind::Infer(..))
@@ -3200,7 +3307,9 @@ pub enum InferDelegationKind {
/// The various kinds of types recognized by the compiler.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir> {
// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
#[repr(u8, C)]
pub enum TyKind<'hir, Unambig = ()> {
/// Actual type should be inherited from `DefId` signature
InferDelegation(DefId, InferDelegationKind),
/// A variable length slice (i.e., `[T]`).
@@ -3230,21 +3339,22 @@ pub enum TyKind<'hir> {
TraitAscription(GenericBounds<'hir>),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
///
/// We use pointer tagging to represent a `&'hir Lifetime` and `TraitObjectSyntax` pair
/// as otherwise this type being `repr(C)` would result in `TyKind` increasing in size.
TraitObject(&'hir [PolyTraitRef<'hir>], TaggedRef<'hir, Lifetime, TraitObjectSyntax>),
/// Unused for now.
Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
///
/// **Note:** Not all inferred types are represented as
/// `TyKind::Infer`. In cases where it is ambiguous whether
/// a generic arg is a type or a const, inference variables are
/// represented as `GenericArg::Infer` instead.
Infer,
/// Placeholder for a type that has failed to be defined.
Err(rustc_span::ErrorGuaranteed),
/// Pattern types (`pattern_type!(u32 is 1..)`)
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
///
/// This variant is not always used to represent inference types, sometimes
/// [`GenericArg::Infer`] is used instead.
Infer(Unambig),
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -4537,3 +4647,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
}
DebugFn(f)
}
#[cfg(test)]
mod tests;
+83
View File
@@ -0,0 +1,83 @@
use rustc_span::def_id::DefIndex;
use super::*;
macro_rules! define_tests {
($($name:ident $kind:ident $variant:ident {$($init:tt)*})*) => {$(
#[test]
fn $name() {
let unambig = $kind::$variant::<'_, ()> { $($init)* };
let unambig_to_ambig = unsafe { std::mem::transmute::<_, $kind<'_, AmbigArg>>(unambig) };
assert!(matches!(&unambig_to_ambig, $kind::$variant { $($init)* }));
let ambig_to_unambig = unsafe { std::mem::transmute::<_, $kind<'_, ()>>(unambig_to_ambig) };
assert!(matches!(&ambig_to_unambig, $kind::$variant { $($init)* }));
}
)*};
}
define_tests! {
cast_never TyKind Never {}
cast_tup TyKind Tup { 0: &[Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }] }
cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }}
cast_array TyKind Array {
0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never },
1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst {
hir_id: HirId::INVALID,
def_id: LocalDefId { local_def_index: DefIndex::ZERO },
body: BodyId { hir_id: HirId::INVALID },
span: DUMMY_SP,
})}
}
cast_anon ConstArgKind Anon {
0: &AnonConst {
hir_id: HirId::INVALID,
def_id: LocalDefId { local_def_index: DefIndex::ZERO },
body: BodyId { hir_id: HirId::INVALID },
span: DUMMY_SP,
}
}
}
#[test]
fn trait_object_roundtrips() {
trait_object_roundtrips_impl(TraitObjectSyntax::Dyn);
trait_object_roundtrips_impl(TraitObjectSyntax::DynStar);
trait_object_roundtrips_impl(TraitObjectSyntax::None);
}
fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
let unambig = TyKind::TraitObject::<'_, ()>(
&[],
TaggedRef::new(
&const {
Lifetime {
hir_id: HirId::INVALID,
ident: Ident::new(sym::name, DUMMY_SP),
res: LifetimeName::Static,
}
},
syntax,
),
);
let unambig_to_ambig = unsafe { std::mem::transmute::<_, TyKind<'_, AmbigArg>>(unambig) };
match unambig_to_ambig {
TyKind::TraitObject(_, tagged_ref) => {
assert!(tagged_ref.tag() == syntax)
}
_ => panic!("`TyKind::TraitObject` did not roundtrip"),
};
let ambig_to_unambig = unsafe { std::mem::transmute::<_, TyKind<'_, ()>>(unambig_to_ambig) };
match ambig_to_unambig {
TyKind::TraitObject(_, tagged_ref) => {
assert!(tagged_ref.tag() == syntax)
}
_ => panic!("`TyKind::TraitObject` did not roundtrip"),
};
}
+149 -77
View File
@@ -351,18 +351,48 @@ fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
walk_inline_const(self, c)
}
fn visit_const_arg(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_const_arg(self, c)
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
walk_generic_arg(self, generic_arg)
}
/// All types are treated as ambiguous types for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
/// ambiguous.
///
/// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
walk_ty(self, t)
}
/// All consts are treated as ambiguous consts for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
/// ambiguous.
///
/// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
walk_ambig_const_arg(self, c)
}
#[allow(unused_variables)]
fn visit_infer(&mut self, inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
self.visit_id(inf_id)
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
walk_lifetime(self, lifetime)
}
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
walk_expr(self, ex)
}
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
walk_expr_field(self, field)
}
fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_ty(self, t)
}
fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
// Do nothing. Only a few visitors need to know the details of the pattern type,
// and they opt into it. All other visitors will just choke on our fake patterns
@@ -444,15 +474,6 @@ fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result {
fn visit_label(&mut self, label: &'v Label) -> Self::Result {
walk_label(self, label)
}
fn visit_infer(&mut self, inf: &'v InferArg) -> Self::Result {
walk_inf(self, inf)
}
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
walk_generic_arg(self, generic_arg)
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
walk_lifetime(self, lifetime)
}
// The span is that of the surrounding type/pattern/expr/whatever.
fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) -> Self::Result {
walk_qpath(self, qpath, id)
@@ -486,6 +507,26 @@ fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, id: HirId) -> Self::Resul
}
}
pub trait VisitorExt<'v>: Visitor<'v> {
/// Extension trait method to visit types in unambiguous positions, this is not
/// directly on the [`Visitor`] trait as this method should never be overridden.
///
/// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery
/// by IDes when `v.visit_ty` is written.
fn visit_ty_unambig(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_unambig_ty(self, t)
}
/// Extension trait method to visit consts in unambiguous positions, this is not
/// directly on the [`Visitor`] trait as this method should never be overridden.
///
/// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in
/// discovery by IDes when `v.visit_const_arg` is written.
fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_const_arg(self, c)
}
}
impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {}
pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result {
try_visit!(visitor.visit_id(param.hir_id));
visitor.visit_pat(param.pat)
@@ -503,12 +544,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
}
ItemKind::Static(ref typ, _, body) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_nested_body(body));
}
ItemKind::Const(ref typ, ref generics, body) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_nested_body(body));
}
@@ -539,7 +580,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
}
ItemKind::TyAlias(ref ty, ref generics) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_generics(generics));
}
ItemKind::Enum(ref enum_definition, ref generics) => {
@@ -561,7 +602,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_generics(generics));
visit_opt!(visitor, visit_trait_ref, of_trait);
try_visit!(visitor.visit_ty(self_ty));
try_visit!(visitor.visit_ty_unambig(self_ty));
walk_list!(visitor, visit_impl_item_ref, *items);
}
ItemKind::Struct(ref struct_definition, ref generics)
@@ -618,7 +659,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
walk_list!(visitor, visit_ident, param_names.iter().copied());
}
ForeignItemKind::Static(ref typ, _, _) => {
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
}
ForeignItemKind::Type => (),
}
@@ -632,7 +673,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -
try_visit!(visitor.visit_id(local.hir_id));
try_visit!(visitor.visit_pat(local.pat));
visit_opt!(visitor, visit_block, local.els);
visit_opt!(visitor, visit_ty, local.ty);
visit_opt!(visitor, visit_ty_unambig, local.ty);
V::Result::output()
}
@@ -735,18 +776,6 @@ pub fn walk_inline_const<'v, V: Visitor<'v>>(
visitor.visit_nested_body(constant.body)
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
try_visit!(visitor.visit_id(const_arg.hir_id));
match &const_arg.kind {
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
ConstArgKind::Infer(..) => V::Result::output(),
}
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
try_visit!(visitor.visit_id(expression.hir_id));
match expression.kind {
@@ -758,7 +787,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
}
ExprKind::Repeat(ref element, ref count) => {
try_visit!(visitor.visit_expr(element));
try_visit!(visitor.visit_const_arg(count));
try_visit!(visitor.visit_const_arg_unambig(count));
}
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span));
@@ -789,7 +818,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
}
ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
try_visit!(visitor.visit_expr(subexpression));
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
}
ExprKind::DropTemps(ref subexpression) => {
try_visit!(visitor.visit_expr(subexpression));
@@ -798,7 +827,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
// match the visit order in walk_local
try_visit!(visitor.visit_expr(init));
try_visit!(visitor.visit_pat(pat));
visit_opt!(visitor, visit_ty, ty);
visit_opt!(visitor, visit_ty_unambig, ty);
}
ExprKind::If(ref cond, ref then, ref else_opt) => {
try_visit!(visitor.visit_expr(cond));
@@ -866,7 +895,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
try_visit!(visitor.visit_inline_asm(asm, expression.hir_id));
}
ExprKind::OffsetOf(ref container, ref fields) => {
try_visit!(visitor.visit_ty(container));
try_visit!(visitor.visit_ty_unambig(container));
walk_list!(visitor, visit_ident, fields.iter().copied());
}
ExprKind::Yield(ref subexpression, _) => {
@@ -874,7 +903,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty, ty);
visit_opt!(visitor, visit_ty_unambig, ty);
}
ExprKind::Lit(_) | ExprKind::Err(_) => {}
}
@@ -886,20 +915,49 @@ pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField
try_visit!(visitor.visit_ident(field.ident));
visitor.visit_expr(field.expr)
}
/// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that
/// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited
pub enum InferKind<'hir> {
Ty(&'hir Ty<'hir>),
Const(&'hir ConstArg<'hir>),
Ambig(&'hir InferArg),
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
pub fn walk_generic_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
generic_arg: &'v GenericArg<'v>,
) -> V::Result {
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
GenericArg::Infer(inf) => visitor.visit_infer(inf.hir_id, inf.span, InferKind::Ambig(inf)),
}
}
pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
match typ.try_as_ambig_ty() {
Some(ambig_ty) => visitor.visit_ty(ambig_ty),
None => {
try_visit!(visitor.visit_id(typ.hir_id));
visitor.visit_infer(typ.hir_id, typ.span, InferKind::Ty(typ))
}
}
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result {
try_visit!(visitor.visit_id(typ.hir_id));
match typ.kind {
TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty(ty)),
TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty(mutable_type.ty)),
TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)),
TyKind::Ref(ref lifetime, ref mutable_type) => {
try_visit!(visitor.visit_lifetime(lifetime));
try_visit!(visitor.visit_ty(mutable_type.ty));
try_visit!(visitor.visit_ty_unambig(mutable_type.ty));
}
TyKind::Never => {}
TyKind::Tup(tuple_element_types) => {
walk_list!(visitor, visit_ty, tuple_element_types);
walk_list!(visitor, visit_ty_unambig, tuple_element_types);
}
TyKind::BareFn(ref function_declaration) => {
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
@@ -907,7 +965,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
}
TyKind::UnsafeBinder(ref unsafe_binder) => {
walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
try_visit!(visitor.visit_ty_unambig(unsafe_binder.inner_ty));
}
TyKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
@@ -919,25 +977,49 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
walk_list!(visitor, visit_param_bound, bounds);
}
TyKind::Array(ref ty, ref length) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_const_arg(length));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_const_arg_unambig(length));
}
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
TyKind::TraitObject(bounds, ref lifetime) => {
for bound in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound));
}
try_visit!(visitor.visit_lifetime(lifetime));
}
TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
TyKind::InferDelegation(..) | TyKind::Err(_) => {}
TyKind::Pat(ty, pat) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_pattern_type_pattern(pat));
}
}
V::Result::output()
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
match const_arg.try_as_ambig_ct() {
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
None => {
try_visit!(visitor.visit_id(const_arg.hir_id));
visitor.visit_infer(const_arg.hir_id, const_arg.span(), InferKind::Const(const_arg))
}
}
}
pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v, AmbigArg>,
) -> V::Result {
try_visit!(visitor.visit_id(const_arg.hir_id));
match &const_arg.kind {
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
}
}
pub fn walk_generic_param<'v, V: Visitor<'v>>(
visitor: &mut V,
param: &'v GenericParam<'v>,
@@ -949,9 +1031,11 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
}
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
GenericParamKind::Type { ref default, .. } => {
visit_opt!(visitor, visit_ty_unambig, default)
}
GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
if let Some(ref default) = default {
try_visit!(visitor.visit_const_param_default(param.hir_id, default));
}
@@ -964,7 +1048,7 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(
visitor: &mut V,
ct: &'v ConstArg<'v>,
) -> V::Result {
visitor.visit_const_arg(ct)
visitor.visit_const_arg_unambig(ct)
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
@@ -986,7 +1070,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
bound_generic_params,
origin: _,
}) => {
try_visit!(visitor.visit_ty(bounded_ty));
try_visit!(visitor.visit_ty_unambig(bounded_ty));
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
@@ -999,8 +1083,8 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
walk_list!(visitor, visit_param_bound, bounds);
}
WherePredicateKind::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty }) => {
try_visit!(visitor.visit_ty(lhs_ty));
try_visit!(visitor.visit_ty(rhs_ty));
try_visit!(visitor.visit_ty_unambig(lhs_ty));
try_visit!(visitor.visit_ty_unambig(rhs_ty));
}
}
V::Result::output()
@@ -1010,13 +1094,13 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(
visitor: &mut V,
function_declaration: &'v FnDecl<'v>,
) -> V::Result {
walk_list!(visitor, visit_ty, function_declaration.inputs);
walk_list!(visitor, visit_ty_unambig, function_declaration.inputs);
visitor.visit_fn_ret_ty(&function_declaration.output)
}
pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result {
if let FnRetTy::Return(output_ty) = *ret_ty {
try_visit!(visitor.visit_ty(output_ty));
try_visit!(visitor.visit_ty_unambig(output_ty));
}
V::Result::output()
}
@@ -1069,7 +1153,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_id(hir_id));
match *kind {
TraitItemKind::Const(ref ty, default) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
visit_opt!(visitor, visit_nested_body, default);
}
TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
@@ -1087,7 +1171,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
}
TraitItemKind::Type(bounds, ref default) => {
walk_list!(visitor, visit_param_bound, bounds);
visit_opt!(visitor, visit_ty, default);
visit_opt!(visitor, visit_ty_unambig, default);
}
}
V::Result::output()
@@ -1125,7 +1209,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_id(impl_item.hir_id()));
match *kind {
ImplItemKind::Const(ref ty, body) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
visitor.visit_nested_body(body)
}
ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn(
@@ -1135,7 +1219,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
impl_item.span,
impl_item.owner_id.def_id,
),
ImplItemKind::Type(ref ty) => visitor.visit_ty(ty),
ImplItemKind::Type(ref ty) => visitor.visit_ty_unambig(ty),
}
}
@@ -1223,7 +1307,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
visit_opt!(visitor, visit_anon_const, default);
visitor.visit_ty(*ty)
visitor.visit_ty_unambig(*ty)
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(
@@ -1252,18 +1336,6 @@ pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Re
visitor.visit_id(inf.hir_id)
}
pub fn walk_generic_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
generic_arg: &'v GenericArg<'v>,
) -> V::Result {
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
GenericArg::Infer(inf) => visitor.visit_infer(inf),
}
}
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result {
try_visit!(visitor.visit_id(lifetime.hir_id));
visitor.visit_ident(lifetime.ident)
@@ -1276,11 +1348,11 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
) -> V::Result {
match *qpath {
QPath::Resolved(ref maybe_qself, ref path) => {
visit_opt!(visitor, visit_ty, maybe_qself);
visit_opt!(visitor, visit_ty_unambig, maybe_qself);
visitor.visit_path(path, id)
}
QPath::TypeRelative(ref qself, ref segment) => {
try_visit!(visitor.visit_ty(qself));
try_visit!(visitor.visit_ty_unambig(qself));
visitor.visit_path_segment(segment)
}
QPath::LangItem(..) => V::Result::output(),
@@ -1320,8 +1392,8 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_generic_args(constraint.gen_args));
match constraint.kind {
AssocItemConstraintKind::Equality { ref term } => match term {
Term::Ty(ref ty) => try_visit!(visitor.visit_ty(ty)),
Term::Const(ref c) => try_visit!(visitor.visit_const_arg(c)),
Term::Ty(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
Term::Const(ref c) => try_visit!(visitor.visit_const_arg_unambig(c)),
},
AssocItemConstraintKind::Bound { bounds } => {
walk_list!(visitor, visit_param_bound, bounds)
+1
View File
@@ -6,6 +6,7 @@
#![allow(internal_features)]
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(exhaustive_patterns)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(rustc_attrs)]
@@ -6,9 +6,9 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{GenericParamKind, ImplItemKind, intravisit};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
@@ -1610,7 +1610,7 @@ fn compare_synthetic_generics<'tcx>(
struct Visitor(hir::def_id::LocalDefId);
impl<'v> intravisit::Visitor<'v> for Visitor {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) -> Self::Result {
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
&& let Res::Def(DefKind::TyParam, def_id) = path.res
&& def_id == self.0.to_def_id()
@@ -1622,9 +1622,9 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
}
}
let span = input_tys.iter().find_map(|ty| {
intravisit::Visitor::visit_ty(&mut Visitor(impl_def_id), ty).break_value()
})?;
let span = input_tys
.iter()
.find_map(|ty| Visitor(impl_def_id).visit_ty_unambig(ty).break_value())?;
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
let bounds = bounds.first()?.span().to(bounds.last()?.span());
@@ -6,10 +6,10 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::ItemKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AmbigArg, ItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_macros::LintDiagnostic;
@@ -2196,7 +2196,7 @@ fn visit_generics(&mut self, _g: &'tcx rustc_hir::Generics<'tcx>) -> Self::Resul
// Skip the generics. We only care about fields, not where clause/param bounds.
}
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind {
if let Res::Def(DefKind::TyParam, def_id) = qpath.res
&& def_id == self.param_def_id
+10 -27
View File
@@ -28,7 +28,7 @@
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor, walk_generics};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics};
use rustc_hir::{self as hir, GenericParamKind, HirId, Node};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
@@ -139,29 +139,12 @@ pub(crate) struct HirPlaceholderCollector {
}
impl<'v> Visitor<'v> for HirPlaceholderCollector {
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
if let hir::TyKind::Infer = t.kind {
self.spans.push(t.span);
}
intravisit::walk_ty(self, t)
}
fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
match generic_arg {
hir::GenericArg::Infer(inf) => {
self.spans.push(inf.span);
self.may_contain_const_infer = true;
intravisit::walk_inf(self, inf);
}
hir::GenericArg::Type(t) => self.visit_ty(t),
_ => {}
}
}
fn visit_const_arg(&mut self, const_arg: &'v hir::ConstArg<'v>) {
if let hir::ConstArgKind::Infer(span) = const_arg.kind {
fn visit_infer(&mut self, _inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
self.spans.push(inf_span);
if let InferKind::Const(_) | InferKind::Ambig(_) = kind {
self.may_contain_const_infer = true;
self.spans.push(span);
}
intravisit::walk_const_arg(self, const_arg)
}
}
@@ -583,7 +566,7 @@ fn lower_fn_sig(
.iter()
.enumerate()
.map(|(i, a)| {
if let hir::TyKind::Infer = a.kind {
if let hir::TyKind::Infer(()) = a.kind {
if let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
@@ -593,21 +576,21 @@ fn lower_fn_sig(
}
// Only visit the type looking for `_` if we didn't fix the type above
visitor.visit_ty(a);
visitor.visit_ty_unambig(a);
self.lowerer().lower_arg_ty(a, None)
})
.collect();
let output_ty = match decl.output {
hir::FnRetTy::Return(output) => {
if let hir::TyKind::Infer = output.kind
if let hir::TyKind::Infer(()) = output.kind
&& let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
{
infer_replacements.push((output.span, suggested_ty.to_string()));
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
} else {
visitor.visit_ty(output);
visitor.visit_ty_unambig(output);
self.lower_ty(output)
}
}
@@ -1453,7 +1436,7 @@ fn recover_infer_ret_ty<'tcx>(
});
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(infer_ret_ty);
visitor.visit_ty_unambig(infer_ret_ty);
let mut diag = bad_placeholder(icx.lowerer(), visitor.spans, "return type");
let ret_ty = fn_sig.output();
@@ -3,9 +3,10 @@
use hir::intravisit::{self, Visitor};
use hir::{GenericParamKind, HirId, Node};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint;
use rustc_span::{Span, Symbol, kw};
@@ -461,7 +462,7 @@ struct LateBoundRegionsDetector<'tcx> {
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) -> ControlFlow<Span> {
match ty.kind {
hir::TyKind::BareFn(..) => {
self.outer_index.shift_in(1);
@@ -539,7 +540,7 @@ fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result
if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind {
let prev = self.in_param_ty;
self.in_param_ty = true;
let res = self.visit_ty(ty);
let res = self.visit_ty_unambig(ty);
self.in_param_ty = prev;
res
} else {
@@ -14,11 +14,11 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
use rustc_hir::{
GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
LifetimeName, Node,
};
use rustc_macros::extension;
use rustc_middle::hir::nested_filter;
@@ -489,15 +489,17 @@ fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
struct FindInferInClosureWithBinder;
impl<'v> Visitor<'v> for FindInferInClosureWithBinder {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
if matches!(t.kind, hir::TyKind::Infer) {
ControlFlow::Break(t.span)
} else {
intravisit::walk_ty(self, t)
}
fn visit_infer(
&mut self,
_inf_id: HirId,
inf_span: Span,
_kind: InferKind<'v>,
) -> Self::Result {
ControlFlow::Break(inf_span)
}
}
FindInferInClosureWithBinder.visit_ty(ty).break_value()
FindInferInClosureWithBinder.visit_ty_unambig(ty).break_value()
}
let infer_in_rt_sp = match fn_decl.output {
@@ -749,7 +751,7 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
}
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match ty.kind {
hir::TyKind::BareFn(c) => {
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
@@ -810,7 +812,9 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
intravisit::walk_ty(this, ty);
});
}
hir::TyKind::TraitObject(bounds, lifetime, _) => {
hir::TyKind::TraitObject(bounds, lifetime) => {
let lifetime = lifetime.pointer();
debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
@@ -827,7 +831,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
// use the object lifetime defaulting
// rules. So e.g., `Box<dyn Debug>` becomes
// `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(lifetime)
self.resolve_object_lifetime_default(&*lifetime)
}
LifetimeName::Infer => {
// If the user writes `'_`, we use the *ordinary* elision
@@ -838,7 +842,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
}
LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime);
self.visit_lifetime(&*lifetime);
}
LifetimeName::Error => {}
}
@@ -849,7 +853,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
s: self.scope,
};
self.with(scope, |this| this.visit_ty(mt.ty));
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
}
hir::TyKind::TraitAscription(bounds) => {
let scope = Scope::TraitRefBoundary { s: self.scope };
@@ -891,7 +895,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
this.visit_param_bound(bound);
}
if let Some(ty) = ty {
this.visit_ty(ty);
this.visit_ty_unambig(ty);
}
})
}
@@ -910,7 +914,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
}),
Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
this.visit_generics(impl_item.generics);
this.visit_ty(ty);
this.visit_ty_unambig(ty);
}),
Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
intravisit::walk_impl_item(this, impl_item)
@@ -1019,7 +1023,7 @@ fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>)
};
self.with(scope, |this| {
walk_list!(this, visit_generic_param, bound_generic_params);
this.visit_ty(bounded_ty);
this.visit_ty_unambig(bounded_ty);
walk_list!(this, visit_param_bound, bounds);
})
}
@@ -1034,8 +1038,8 @@ fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>)
&hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
lhs_ty, rhs_ty, ..
}) => {
self.visit_ty(lhs_ty);
self.visit_ty(rhs_ty);
self.visit_ty_unambig(lhs_ty);
self.visit_ty_unambig(rhs_ty);
}
}
}
@@ -1068,13 +1072,13 @@ fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { default, .. } => {
if let Some(ty) = default {
self.visit_ty(ty);
self.visit_ty_unambig(ty);
}
}
GenericParamKind::Const { ty, default, .. } => {
self.visit_ty(ty);
self.visit_ty_unambig(ty);
if let Some(default) = default {
self.visit_const_arg(default);
self.visit_const_arg_unambig(default);
}
}
}
@@ -1983,15 +1987,15 @@ fn visit_fn_like_elision(
},
|this| {
for input in inputs {
this.visit_ty(input);
this.visit_ty_unambig(input);
}
if !in_closure && let Some(output) = output {
this.visit_ty(output);
this.visit_ty_unambig(output);
}
},
);
if in_closure && let Some(output) = output {
self.visit_ty(output);
self.visit_ty_unambig(output);
}
}
@@ -2309,7 +2313,7 @@ fn is_late_bound_map(
let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
for arg_ty in sig.decl.inputs {
constrained_by_input.visit_ty(arg_ty);
constrained_by_input.visit_ty_unambig(arg_ty);
}
let mut appears_in_output =
@@ -2417,7 +2421,7 @@ struct ConstrainedCollector<'tcx> {
}
impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
match ty.kind {
hir::TyKind::Path(
hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..),
@@ -1,10 +1,9 @@
use core::ops::ControlFlow;
use rustc_errors::{Applicability, StashKey, Suggestions};
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg, HirId};
use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::fold::fold_regions;
use rustc_middle::ty::print::with_forced_trimmed_paths;
@@ -451,7 +450,7 @@ fn infer_placeholder_type<'tcx>(
let mut visitor = HirPlaceholderCollector::default();
let node = tcx.hir_node_by_def_id(def_id);
if let Some(ty) = node.ty() {
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
}
// If we have just one span, let's try to steal a const `_` feature error.
let try_steal_span = if !tcx.features().generic_arg_infer() && visitor.spans.len() == 1
@@ -525,7 +524,7 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
struct HasTait;
impl<'tcx> Visitor<'tcx> for HasTait {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
if let hir::TyKind::OpaqueDef(..) = t.kind {
ControlFlow::Break(())
} else {
@@ -533,5 +532,5 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
}
}
}
HasTait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
HasTait.visit_ty_unambig(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
}
@@ -1,10 +1,9 @@
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::GenericArg;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, GenericArg};
use rustc_middle::ty::{
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
};
@@ -41,17 +40,6 @@ fn generic_arg_mismatch_err(
param.kind.descr(),
);
if let GenericParamDefKind::Const { .. } = param.kind {
if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
err.help("const arguments cannot yet be inferred with `_`");
tcx.disabled_nightly_features(
&mut err,
param.def_id.as_local().map(|local| tcx.local_def_id_to_hir_id(local)),
[(String::new(), sym::generic_arg_infer)],
);
}
}
let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diag<'_>| {
let suggestions = vec![
(arg.span().shrink_to_lo(), String::from("{ ")),
@@ -270,6 +258,21 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
GenericParamDefKind::Const { .. },
_,
) => {
if let GenericParamDefKind::Const { .. } = param.kind
&& let GenericArg::Infer(inf) = arg
&& !tcx.features().generic_arg_infer()
{
rustc_session::parse::feature_err(
tcx.sess,
sym::generic_arg_infer,
inf.span,
"const arguments cannot yet be inferred with `_`",
)
.emit();
}
// We lower to an infer even when the feature gate is not enabled
// as it is useful for diagnostics to be able to see a `ConstKind::Infer`
args.push(ctx.provided_kind(&args, param, arg));
args_iter.next();
params.next();
@@ -23,9 +23,12 @@ pub(super) fn prohibit_or_lint_bare_trait_object_ty(
) -> Option<ErrorGuaranteed> {
let tcx = self.tcx();
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
self_ty.kind
else {
&& let TraitObjectSyntax::None = tagged_ptr.tag()
{
poly_trait_ref
} else {
return None;
};
@@ -294,7 +297,7 @@ fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -
let (dyn_str, paren_dyn_str) =
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
// There are more than one trait bound, we need surrounding parentheses.
vec![
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
@@ -517,14 +517,17 @@ fn provided_kind(
self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
handle_ty_args(has_default, ty)
// We handle the other parts of `Ty` in the match arm below
handle_ty_args(has_default, ty.as_unambig_ty())
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => {
handle_ty_args(has_default, &inf.to_ty())
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.lowerer
// Ambig portions of `ConstArg` are handled in the match arm below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.into(),
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.lowerer.ct_infer(Some(param), inf.span).into()
}
@@ -2115,7 +2118,7 @@ pub fn lower_const_arg(
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
),
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
}
}
@@ -2311,7 +2314,10 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
tcx.late_bound_vars(hir_ty.hir_id),
),
),
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
hir::TyKind::TraitObject(bounds, tagged_ptr) => {
let lifetime = tagged_ptr.pointer();
let repr = tagged_ptr.tag();
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
// Don't continue with type analysis if the `dyn` keyword is missing
// It generates confusing errors, especially if the user meant to use another
@@ -2420,7 +2426,7 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)
}
hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(),
hir::TyKind::Infer => {
hir::TyKind::Infer(()) => {
// Infer also appears as the type of arguments or return
// values in an ExprKind::Closure, or as
// the type of local variables. Both of these cases are
@@ -2553,7 +2559,7 @@ fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
match ty.kind {
hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => {
self.record_ty(ty.hir_id, expected_ty, ty.span);
expected_ty
}
@@ -1,6 +1,5 @@
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ForeignItem, ForeignItemKind};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::bug;
@@ -68,11 +67,13 @@ struct HirWfCheck<'tcx> {
}
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let tcx_ty = self.icx.lower_ty(ty);
// We don't handle infer vars but we wouldn't handle them anyway as we're creating a
// fresh `InferCtxt` in this function.
let tcx_ty = self.icx.lower_ty(ty.as_unambig_ty());
// This visitor can walk into binders, resulting in the `tcx_ty` to
// potentially reference escaping bound variables. We simply erase
// those here.
@@ -149,7 +150,11 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
.iter()
.flat_map(|seg| seg.args().args)
.filter_map(|arg| {
if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
if let hir::GenericArg::Type(ty) = arg {
Some(ty.as_unambig_ty())
} else {
None
}
})
.chain([impl_.self_ty])
.collect(),
@@ -196,7 +201,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
}
};
for ty in tys {
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
}
visitor.cause
}
+7 -6
View File
@@ -402,7 +402,8 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
self.print_bounds("impl", bounds);
}
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
hir::TyKind::TraitObject(bounds, lifetime) => {
let syntax = lifetime.tag();
match syntax {
ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
@@ -421,7 +422,7 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
if !lifetime.is_elided() {
self.nbsp();
self.word_space("+");
self.print_lifetime(lifetime);
self.print_lifetime(lifetime.pointer());
}
}
hir::TyKind::Array(ty, ref length) => {
@@ -441,7 +442,7 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
self.word("/*ERROR*/");
self.pclose();
}
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
hir::TyKind::Infer(()) | hir::TyKind::InferDelegation(..) => {
self.word("_");
}
hir::TyKind::Pat(ty, pat) => {
@@ -1799,8 +1800,8 @@ fn print_generic_args(
match generic_arg {
GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
GenericArg::Lifetime(_) => {}
GenericArg::Type(ty) => s.print_type(ty),
GenericArg::Const(ct) => s.print_const_arg(ct),
GenericArg::Type(ty) => s.print_type(ty.as_unambig_ty()),
GenericArg::Const(ct) => s.print_const_arg(ct.as_unambig_ct()),
GenericArg::Infer(_inf) => s.word("_"),
}
});
@@ -2150,7 +2151,7 @@ fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId)
s.ann.nested(s, Nested::BodyParamPat(body_id, i));
i += 1;
if let hir::TyKind::Infer = ty.kind {
if let hir::TyKind::Infer(()) = ty.kind {
// Print nothing.
} else {
s.word(":");
+11 -6
View File
@@ -10,7 +10,7 @@
use rustc_hir::HirId;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{InferKind, Visitor};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
@@ -641,16 +641,21 @@ fn suggest_for_segment(
impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
type Result = ControlFlow<errors::SuggestAnnotation>;
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_infer(
&mut self,
inf_id: HirId,
inf_span: Span,
_kind: InferKind<'tcx>,
) -> Self::Result {
// Try to replace `_` with `()`.
if let hir::TyKind::Infer = hir_ty.kind
&& let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(hir_ty.hir_id)
if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id)
&& let Some(vid) = self.fcx.root_vid(ty)
&& self.reachable_vids.contains(&vid)
{
return ControlFlow::Break(errors::SuggestAnnotation::Unit(hir_ty.span));
return ControlFlow::Break(errors::SuggestAnnotation::Unit(inf_span));
}
hir::intravisit::walk_ty(self, hir_ty)
ControlFlow::Continue(())
}
fn visit_qpath(
+12 -9
View File
@@ -6,9 +6,9 @@
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
use rustc_hir::{self as hir, AmbigArg, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
use rustc_hir_analysis::hir_ty_lowering::generics::{
check_generic_arg_count_for_call, lower_generic_args,
@@ -470,7 +470,7 @@ struct CollectClauses<'a, 'tcx> {
}
impl<'tcx> intravisit::Visitor<'tcx> for CollectClauses<'_, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let Some(clauses) = self.fcx.trait_ascriptions.borrow().get(&ty.hir_id.local_id)
{
self.clauses.extend(clauses.iter().cloned());
@@ -480,7 +480,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
}
let mut clauses = CollectClauses { clauses: vec![], fcx: self };
clauses.visit_ty(hir_ty);
clauses.visit_ty_unambig(hir_ty);
self.tcx.mk_clauses(&clauses.clauses)
}
@@ -1272,14 +1272,17 @@ fn provided_kind(
.lower_lifetime(lt, RegionInferReason::Param(param))
.into(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.fcx.lower_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.fcx.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
// We handle the ambig portions of `Ty` in match arm below
self.fcx.lower_ty(ty.as_unambig_ty()).raw.into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.fcx.ty_infer(Some(param), inf.span).into()
self.fcx.lower_ty(&inf.to_ty()).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.fcx
// Ambiguous parts of `ConstArg` are handled in the match arms below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.into(),
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.fcx.ct_infer(Some(param), inf.span).into()
}
+2 -1
View File
@@ -251,7 +251,8 @@ fn typeck_with_inspect<'tcx>(
fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option<Ty<'tcx>> {
let tcx = fcx.tcx;
let def_id = fcx.body_id;
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = node.ty() {
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
{
if let Some(item) = tcx.opt_associated_item(def_id.into())
&& let ty::AssocKind::Const = item.kind
&& let ty::AssocItemContainer::Impl = item.container
@@ -425,14 +425,17 @@ fn provided_kind(
.lower_lifetime(lt, RegionInferReason::Param(param))
.into(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.cfcx.lower_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.cfcx.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
// We handle the ambig portions of `Ty` in the match arms below
self.cfcx.lower_ty(ty.as_unambig_ty()).raw.into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.cfcx.ty_infer(Some(param), inf.span).into()
self.cfcx.lower_ty(&inf.to_ty()).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.cfcx
// We handle the ambig portions of `ConstArg` in the match arms below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.into(),
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.cfcx.ct_infer(Some(param), inf.span).into()
}
+17 -10
View File
@@ -6,9 +6,8 @@
use rustc_data_structures::unord::ExtendUnord;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, InferKind, Visitor};
use rustc_hir::{self as hir, AmbigArg, HirId};
use rustc_middle::span_bug;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -354,7 +353,7 @@ fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
self.write_ty_to_typeck_results(l.hir_id, var_ty);
}
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
intravisit::walk_ty(self, hir_ty);
// If there are type checking errors, Type privacy pass will stop,
// so we may not get the type from hid_id, see #104513
@@ -364,12 +363,20 @@ fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
}
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
intravisit::walk_inf(self, inf);
// Ignore cases where the inference is a const.
if let Some(ty) = self.fcx.node_ty_opt(inf.hir_id) {
let ty = self.resolve(ty, &inf.span);
self.write_ty_to_typeck_results(inf.hir_id, ty);
fn visit_infer(
&mut self,
inf_id: HirId,
inf_span: Span,
_kind: InferKind<'cx>,
) -> Self::Result {
self.visit_id(inf_id);
// We don't currently write inference results of const infer vars to
// the typeck results as there is not yet any part of the compiler that
// needs this information.
if let Some(ty) = self.fcx.node_ty_opt(inf_id) {
let ty = self.resolve(ty, &inf_span);
self.write_ty_to_typeck_results(inf_id, ty);
}
}
}
+3 -3
View File
@@ -5,8 +5,8 @@
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{
BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind,
Path, PathSegment, QPath, Ty, TyKind,
AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
PatKind, Path, PathSegment, QPath, Ty, TyKind,
};
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -159,7 +159,7 @@ fn check_path(
}
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) {
+2 -7
View File
@@ -8,9 +8,8 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::join;
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::{HirId, intravisit as hir_visit};
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
@@ -214,15 +213,11 @@ fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
})
}
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
lint_callback!(self, check_ty, t);
hir_visit::walk_ty(self, t);
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
hir_visit::walk_inf(self, inf);
}
fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: HirId) {
if !self.context.only_module {
self.process_mod(m, n);
+2 -1
View File
@@ -9,6 +9,7 @@
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, MissingLifetimeKind};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::inhabitedness::InhabitedPredicate;
@@ -293,7 +294,7 @@ fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
// avoid doing throwaway work in case the lint ends up getting suppressed.
let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() };
if let Some(ty) = self.ty {
hir::intravisit::Visitor::visit_ty(&mut collector, ty);
collector.visit_ty_unambig(ty);
}
let affect_object_lifetime_defaults = self
+2 -2
View File
@@ -1,6 +1,6 @@
use rustc_errors::MultiSpan;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
use rustc_middle::ty::TyCtxt;
use rustc_session::{declare_lint, impl_lint_pass};
@@ -126,7 +126,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref
// of the `impl` definition
let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty(&impl_.self_ty);
collector.visit_ty_unambig(&impl_.self_ty);
if let Some(of_trait) = &impl_.of_trait {
collector.visit_trait_ref(of_trait);
}
@@ -1,4 +1,4 @@
use rustc_hir as hir;
use rustc_hir::{self as hir, AmbigArg};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::fold::BottomUpFolder;
@@ -67,7 +67,7 @@
declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let hir::TyKind::OpaqueDef(opaque) = &ty.kind else {
return;
};
+2 -3
View File
@@ -1,6 +1,5 @@
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -22,7 +21,7 @@
declare_lint_pass!(PassByValue => [PASS_BY_VALUE]);
impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
+1 -1
View File
@@ -25,7 +25,7 @@ macro_rules! late_lint_methods {
fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>);
fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>);
fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>);
fn check_ty(a: &'tcx rustc_hir::Ty<'tcx>);
fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>);
fn check_generic_param(a: &'tcx rustc_hir::GenericParam<'tcx>);
fn check_generics(a: &'tcx rustc_hir::Generics<'tcx>);
fn check_poly_trait_ref(a: &'tcx rustc_hir::PolyTraitRef<'tcx>);
+5 -3
View File
@@ -1,4 +1,4 @@
use rustc_hir::{self as hir, LangItem};
use rustc_hir::{self as hir, AmbigArg, LangItem};
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::sym;
@@ -110,8 +110,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let hir::TyKind::TraitObject(bounds, _lifetime_and_syntax_pointer) = &ty.kind else {
return;
};
for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {
+4 -3
View File
@@ -4,7 +4,8 @@
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagMessage;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{AmbigArg, Expr, ExprKind, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
use rustc_middle::ty::{
@@ -1526,7 +1527,7 @@ struct FnPtrFinder<'a, 'b, 'tcx> {
}
impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> {
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
debug!(?ty);
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
&& !self.visitor.is_internal_abi(*abi)
@@ -1554,7 +1555,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() };
ty.visit_with(&mut visitor);
hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);
visitor.visit_ty_unambig(hir_ty);
iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
}
+3 -3
View File
@@ -33,7 +33,7 @@
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate};
use rustc_index::IndexVec;
@@ -2028,7 +2028,7 @@ pub fn return_type_impl_or_dyn_traits(
};
let mut v = TraitObjectVisitor(vec![], self.hir());
v.visit_ty(hir_output);
v.visit_ty_unambig(hir_output);
v.0
}
@@ -2050,7 +2050,7 @@ pub fn return_type_impl_or_dyn_traits_with_type_alias(
&& let Some(alias_ty) = self.hir_node_by_def_id(local_id).alias_ty() // it is type alias
&& let Some(alias_generics) = self.hir_node_by_def_id(local_id).generics()
{
v.visit_ty(alias_ty);
v.visit_ty_unambig(alias_ty);
if !v.0.is_empty() {
return Some((
v.0,
+9 -9
View File
@@ -9,7 +9,7 @@
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicateKind};
use rustc_hir::{self as hir, AmbigArg, LangItem, PredicateOrigin, WherePredicateKind};
use rustc_span::{BytePos, Span};
use rustc_type_ir::TyKind::*;
@@ -570,18 +570,18 @@ pub fn suggest_constraining_type_params<'a>(
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
match ty.kind {
hir::TyKind::TraitObject(
_,
hir::Lifetime {
hir::TyKind::TraitObject(_, tagged_ptr)
if let hir::Lifetime {
res:
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
..
},
_,
)
| hir::TyKind::OpaqueDef(..) => self.0.push(ty),
} = tagged_ptr.pointer() =>
{
self.0.push(ty.as_unambig_ty())
}
hir::TyKind::OpaqueDef(..) => self.0.push(ty.as_unambig_ty()),
_ => {}
}
hir::intravisit::walk_ty(self, ty);
+7 -1
View File
@@ -374,7 +374,13 @@ fn find_item_ty_spans(
if let hir::GenericArg::Type(ty) = arg
&& params_in_repr.contains(i as u32)
{
find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
find_item_ty_spans(
tcx,
ty.as_unambig_ty(),
needle,
spans,
seen_representable,
);
}
}
}
+1 -1
View File
@@ -2808,7 +2808,7 @@ fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
&& let Some(&[hir::GenericArg::Type(ty)]) =
path.segments.last().map(|last| last.args().args)
{
doc_fake_variadic_is_allowed_self_ty(ty)
doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
} else {
false
})
+1 -1
View File
@@ -460,7 +460,7 @@ fn visit_node(&mut self, node: Node<'tcx>) {
}
// mark self_ty live
intravisit::walk_ty(self, impl_ref.self_ty);
intravisit::walk_unambig_ty(self, impl_ref.self_ty);
if let Some(&impl_item_id) =
self.tcx.impl_item_implementor_ids(impl_id).get(&trait_item_id)
{
+3 -4
View File
@@ -5,8 +5,7 @@
use rustc_ast::visit::BoundKind;
use rustc_ast::{self as ast, NodeId, visit as ast_visit};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::{HirId, intravisit as hir_visit};
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::common::to_readable_str;
@@ -363,7 +362,7 @@ fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) {
hir_visit::walk_expr_field(self, f)
}
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, t: &'v hir::Ty<'v, AmbigArg>) {
record_variants!((self, t, t.kind, Some(t.hir_id), hir, Ty, TyKind), [
InferDelegation,
Slice,
@@ -476,7 +475,7 @@ fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) {
hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
hir::GenericArg::Type(ty) => self.visit_ty(ty),
hir::GenericArg::Const(ct) => self.visit_const_arg(ct),
hir::GenericArg::Infer(inf) => self.visit_infer(inf),
hir::GenericArg::Infer(inf) => self.visit_id(inf.hir_id),
}
}
+6 -7
View File
@@ -11,12 +11,11 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
use rustc_middle::middle::privacy::EffectiveVisibilities;
@@ -802,7 +801,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
)) = stab
{
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty(self_ty);
c.visit_ty_unambig(self_ty);
c.visit_trait_ref(t);
// do not lint when the trait isn't resolved, since resolution error should
@@ -1028,7 +1027,7 @@ fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
intravisit::walk_trait_ref(self, t)
}
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
if let TyKind::Never = t.kind {
self.fully_stable = false;
}
@@ -1042,12 +1041,12 @@ fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
for ty in fd.inputs {
self.visit_ty(ty)
self.visit_ty_unambig(ty)
}
if let hir::FnRetTy::Return(output_ty) = fd.output {
match output_ty.kind {
TyKind::Never => {} // `-> !` is stable
_ => self.visit_ty(output_ty),
_ => self.visit_ty_unambig(output_ty),
}
}
}
+14 -8
View File
@@ -27,8 +27,8 @@
use rustc_errors::MultiSpan;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
use rustc_hir::intravisit::{self, InferKind, Visitor};
use rustc_hir::{AmbigArg, AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
use rustc_middle::query::Providers;
use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -1179,7 +1179,7 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
self.maybe_typeck_results = old_maybe_typeck_results;
}
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
self.span = hir_ty.span;
if self
.visit(
@@ -1195,12 +1195,17 @@ fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
intravisit::walk_ty(self, hir_ty);
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
self.span = inf.span;
fn visit_infer(
&mut self,
inf_id: rustc_hir::HirId,
inf_span: Span,
_kind: InferKind<'tcx>,
) -> Self::Result {
self.span = inf_span;
if let Some(ty) = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(inf.span, "`hir::InferArg` outside of a body"))
.node_type_opt(inf.hir_id)
.unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body"))
.node_type_opt(inf_id)
{
if self.visit(ty).is_break() {
return;
@@ -1208,7 +1213,8 @@ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
} else {
// FIXME: check types of const infers here.
}
intravisit::walk_inf(self, inf);
self.visit_id(inf_id)
}
// Check types of expressions
@@ -1,8 +1,8 @@
use core::ops::ControlFlow;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars as rbv;
@@ -48,7 +48,7 @@ fn find_component_for_bound_region<'tcx>(
region_def_id: DefId,
) -> Option<&'tcx hir::Ty<'tcx>> {
FindNestedTypeVisitor { tcx, region_def_id, current_index: ty::INNERMOST }
.visit_ty(arg)
.visit_ty_unambig(arg)
.break_value()
}
@@ -74,7 +74,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
match arg.kind {
hir::TyKind::BareFn(_) => {
self.current_index.shift_in(1);
@@ -101,7 +101,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
Some(rbv::ResolvedArg::EarlyBound(id)) => {
debug!("EarlyBound id={:?}", id);
if id.to_def_id() == self.region_def_id {
return ControlFlow::Break(arg);
return ControlFlow::Break(arg.as_unambig_ty());
}
}
@@ -117,7 +117,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
if debruijn_index == self.current_index
&& id.to_def_id() == self.region_def_id
{
return ControlFlow::Break(arg);
return ControlFlow::Break(arg.as_unambig_ty());
}
}
@@ -147,7 +147,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
)
.is_break()
{
ControlFlow::Break(arg)
ControlFlow::Break(arg.as_unambig_ty())
} else {
ControlFlow::Continue(())
};
@@ -210,7 +210,7 @@ fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result {
ControlFlow::Continue(())
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
// ignore nested types
//
// If you have a type like `Foo<'a, &Ty>` we
@@ -4,7 +4,7 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_middle::bug;
use rustc_middle::ty::TypeVisitor;
use tracing::debug;
@@ -87,7 +87,7 @@ pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaran
for matching_def_id in v.0 {
let mut hir_v =
super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
hir_v.visit_ty(impl_self_ty);
hir_v.visit_ty_unambig(impl_self_ty);
}
if traits.is_empty() {
@@ -3,9 +3,9 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{
self as hir, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
};
use rustc_middle::ty::{
@@ -153,7 +153,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty);
v.visit_ty_unambig(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
spans = v.0;
@@ -374,7 +374,7 @@ pub fn suggest_new_region_bound(
}
}
}
TyKind::TraitObject(_, lt, _) => {
TyKind::TraitObject(_, lt) => {
if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
@@ -500,7 +500,7 @@ pub fn get_impl_ident_and_self_ty_from_trait(
// In that case, only the first one will get suggestions.
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
hir_v.visit_ty(self_ty);
hir_v.visit_ty_unambig(self_ty);
!traits.is_empty()
})
{
@@ -560,7 +560,7 @@ fn suggest_constrain_dyn_trait_in_impl(
for found_did in found_dids {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(self_ty);
hir_v.visit_ty_unambig(self_ty);
for &span in &traits {
let subdiag = DynTraitConstraintSuggestion { span, ident };
subdiag.add_to_diag(err);
@@ -591,12 +591,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
if let TyKind::TraitObject(
poly_trait_refs,
Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. },
_,
) = t.kind
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind
&& let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } =
lifetime_ptr.pointer()
{
for ptr in poly_trait_refs {
if Some(self.1) == ptr.trait_ref.trait_def_id() {
@@ -1,10 +1,10 @@
//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
@@ -137,11 +137,13 @@ fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
match arg.kind {
hir::TyKind::Ref(_, ref mut_ty) => {
// We don't want to suggest looking into borrowing `&T` or `&Self`.
hir::intravisit::walk_ty(self, mut_ty.ty);
if let Some(ambig_ty) = mut_ty.ty.try_as_ambig_ty() {
walk_ty(self, ambig_ty);
}
return;
}
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
@@ -655,7 +655,7 @@ pub(super) fn suggest_for_all_lifetime_closure(
&& let ty::Ref(found_region, _, _) = found.kind()
&& expected_region.is_bound()
&& !found_region.is_bound()
&& let hir::TyKind::Infer = arg_hir.kind
&& let hir::TyKind::Infer(()) = arg_hir.kind
{
// If the expected region is late bound, the found region is not, and users are asking compiler
// to infer the type, we can suggest adding `: &_`.
@@ -580,8 +580,8 @@ pub fn report_selection_error(
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
&& let hir::ItemKind::Impl(impl_) = item.kind
&& let None = impl_.of_trait
&& let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
&& let TraitObjectSyntax::None = syntax
&& let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind
&& let TraitObjectSyntax::None = tagged_ptr.tag()
&& impl_.self_ty.span.edition().at_least_rust_2021()
{
// Silence the dyn-compatibility error in favor of the missing dyn on
@@ -11,7 +11,7 @@
use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, LangItem};
use rustc_hir::{self as hir, AmbigArg, LangItem};
use rustc_infer::traits::{
DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
PredicateObligation, SelectionError,
@@ -87,9 +87,9 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
}
}
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
if self.span == ty.span {
self.ty_result = Some(ty);
self.ty_result = Some(ty.as_unambig_ty());
} else {
hir::intravisit::walk_ty(self, ty);
}
@@ -14,14 +14,13 @@
Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize,
struct_span_code_err,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{Visitor, VisitorExt};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, expr_needs_parens,
is_range_literal,
self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
expr_needs_parens, is_range_literal,
};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_middle::hir::map;
@@ -179,7 +178,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
let mut ty_spans = vec![];
for input in fn_sig.decl.inputs {
ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
.visit_ty(input);
.visit_ty_unambig(input);
}
// The type param `T: Trait` we will suggest to introduce.
let type_param = format!("{type_param_name}: {bound_str}");
@@ -3074,7 +3073,7 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
}
if let Some(ty) = ty {
match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => {
hir::TyKind::TraitObject(traits, _) => {
let (span, kw) = match traits {
[first, ..] if first.span.lo() == ty.span.lo() => {
// Missing `dyn` in front of trait object.
@@ -5065,7 +5064,7 @@ pub struct SelfVisitor<'v> {
}
impl<'v> Visitor<'v> for SelfVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
if let hir::TyKind::Path(path) = ty.kind
&& let hir::QPath::TypeRelative(inner_ty, segment) = path
&& (Some(segment.ident.name) == self.name || self.name.is_none())
@@ -5073,7 +5072,7 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
&& let hir::QPath::Resolved(None, inner_path) = inner_path
&& let Res::SelfTyAlias { .. } = inner_path.res
{
self.paths.push(ty);
self.paths.push(ty.as_unambig_ty());
}
hir::intravisit::walk_ty(self, ty);
}
@@ -5187,7 +5186,7 @@ struct ReplaceImplTraitVisitor<'a> {
}
impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
fn visit_ty(&mut self, t: &'hir hir::Ty<'hir, AmbigArg>) {
if let hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: Res::Def(_, segment_did), .. },
@@ -5480,7 +5479,7 @@ fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
// Skip where-clauses, to avoid suggesting indirection for type parameters found there.
}
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
// valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+6 -7
View File
@@ -6,11 +6,10 @@
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{FnRetTy, GenericParamKind, Node};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
@@ -579,7 +578,7 @@ struct ImplicitLifetimeFinder {
}
impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
let make_suggestion = |ident: Ident| {
if ident.name == kw::Empty && ident.span.is_empty() {
format!("{}, ", self.suggestion_param_name)
@@ -642,16 +641,16 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if let Some(fn_decl) = node.fn_decl()
&& let hir::FnRetTy::Return(ty) = fn_decl.output
{
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
}
if visitor.suggestions.is_empty() {
// Do not suggest constraining the `&self` param, but rather the return type.
// If that is wrong (because it is not sufficient), a follow up error will tell the
// user to fix it. This way we lower the chances of *over* constraining, but still
// get the cake of "correctly" contrained in two steps.
visitor.visit_ty(self.ty_sup);
visitor.visit_ty_unambig(self.ty_sup);
}
visitor.visit_ty(self.ty_sub);
visitor.visit_ty_unambig(self.ty_sub);
if visitor.suggestions.is_empty() {
return false;
}
+2 -2
View File
@@ -1,8 +1,8 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
@@ -187,7 +187,7 @@ struct RPITVisitor {
}
impl<'tcx> Visitor<'tcx> for RPITVisitor {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let hir::TyKind::OpaqueDef(opaq) = ty.kind
&& self.rpits.insert(opaq.def_id)
{
+14 -9
View File
@@ -1747,9 +1747,9 @@ fn maybe_expand_private_type_alias<'tcx>(
};
let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
let provided_params = &path.segments.last().expect("segments were empty");
let final_seg = &path.segments.last().expect("segments were empty");
let mut args = DefIdMap::default();
let generic_args = provided_params.args();
let generic_args = final_seg.args();
let mut indices: hir::GenericParamCount = Default::default();
for param in generics.params.iter() {
@@ -1781,7 +1781,7 @@ fn maybe_expand_private_type_alias<'tcx>(
let type_ = generic_args.args.iter().find_map(|arg| match arg {
hir::GenericArg::Type(ty) => {
if indices.types == j {
return Some(*ty);
return Some(ty.as_unambig_ty());
}
j += 1;
None
@@ -1843,10 +1843,13 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
}
TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, lifetime, _) => {
TyKind::TraitObject(bounds, lifetime) => {
let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
let lifetime =
if !lifetime.is_elided() { Some(clean_lifetime(lifetime, cx)) } else { None };
let lifetime = if !lifetime.is_elided() {
Some(clean_lifetime(lifetime.pointer(), cx))
} else {
None
};
DynTrait(bounds, lifetime)
}
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
@@ -1854,7 +1857,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
UnsafeBinder(Box::new(clean_unsafe_binder_ty(unsafe_binder_ty, cx)))
}
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
TyKind::Infer
TyKind::Infer(())
| TyKind::Err(_)
| TyKind::Typeof(..)
| TyKind::InferDelegation(..)
@@ -2533,8 +2536,10 @@ fn clean_generic_args<'tcx>(
GenericArg::Lifetime(clean_lifetime(lt, cx))
}
hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)),
hir::GenericArg::Const(ct) => {
GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx)))
}
hir::GenericArg::Infer(_inf) => GenericArg::Infer,
})
.collect::<Vec<_>>()
+7 -2
View File
@@ -598,8 +598,13 @@ fn visit_label(&mut self, _: &rustc_ast::Label) {
// Unneeded.
}
fn visit_infer(&mut self, _: &hir::InferArg) {
// Unneeded.
fn visit_infer(
&mut self,
_inf_id: hir::HirId,
_inf_span: Span,
_kind: hir::intravisit::InferKind<'tcx>,
) -> Self::Result {
// Unneeded
}
fn visit_lifetime(&mut self, _: &hir::Lifetime) {
@@ -4,12 +4,12 @@
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 {
@@ -4,7 +4,7 @@
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,
@@ -7,7 +7,7 @@
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() {
@@ -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",
@@ -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);
@@ -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!(
@@ -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!(
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
}
},
// Ignore `p as *const _`
TyKind::Infer => return false,
TyKind::Infer(()) => return false,
_ => {},
}
@@ -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}>()")
@@ -11,10 +11,10 @@
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 @@ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
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 @@ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
| TyKind::Path(_) => Self::Deref,
TyKind::OpaqueDef(..)
| TyKind::TraitAscription(..)
| TyKind::Infer
| TyKind::Infer(())
| TyKind::Typeof(..)
| TyKind::TraitObject(..)
| TyKind::InferDelegation(..)
@@ -889,29 +889,23 @@ fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option<DefId>, ty: Ty<'t
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
}
@@ -6,7 +6,7 @@
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 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
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);
}
@@ -3,7 +3,7 @@
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 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
}
}
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);
}
@@ -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()
{
@@ -3,10 +3,10 @@
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 @@ fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'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);
@@ -103,7 +103,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
"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);
@@ -2,9 +2,8 @@
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 @@ fn suggestion(
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 @@ fn suggestion(
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 @@ fn new(cx: &'a LateContext<'tcx>) -> Self {
}
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`.
@@ -3,8 +3,8 @@
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 @@ fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &rustc_hir::Gener
}
}
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);
}
@@ -28,7 +28,7 @@
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)
+15 -15
View File
@@ -7,13 +7,13 @@
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 @@ fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'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 @@ fn visit_where_bound_predicate(
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);
}
@@ -3,7 +3,7 @@
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 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
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);
}
@@ -6,11 +6,11 @@
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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& 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
}
@@ -80,7 +80,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
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;
}
},
@@ -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(()),
..
})
) {
@@ -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,
}
}
@@ -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 {
+2 -3
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 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
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
@@ -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
}
@@ -2,7 +2,7 @@
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_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
@@ -10,8 +10,8 @@
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 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tc
}
}
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
@@ -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;
}
@@ -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)
@@ -560,7 +560,7 @@ fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, mut
_ => None,
})
}) {
self.check_ty(cx, ty, context);
self.check_ty(cx, ty.as_unambig_ty(), context);
}
},
QPath::Resolved(None, p) => {
@@ -574,7 +574,7 @@ fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, mut
_ => None,
})
}) {
self.check_ty(cx, ty, context);
self.check_ty(cx, ty.as_unambig_ty(), context);
}
},
QPath::TypeRelative(ty, seg) => {
@@ -585,7 +585,7 @@ fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, mut
GenericArg::Type(ty) => Some(ty),
_ => None,
}) {
self.check_ty(cx, ty, context);
self.check_ty(cx, ty.as_unambig_ty(), context);
}
}
},
@@ -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 @@
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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
// 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
@@ -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
}
{
@@ -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 {
+14 -11
View File
@@ -7,10 +7,10 @@
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 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
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 @@ fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
}
}
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 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx>) {
&& 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);
@@ -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_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)
@@ -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("")),
}
@@ -459,9 +459,9 @@ fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool
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 @@ pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
},
(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 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
}
},
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 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
self.hash_ty(binder.inner_ty);
},
TyKind::Err(_)
| TyKind::Infer
| TyKind::Infer(())
| TyKind::Never
| TyKind::InferDelegation(..)
| TyKind::OpaqueDef(_)
@@ -1318,8 +1318,8 @@ fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
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()),
}
}
+2 -2
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 check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> 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))
},
@@ -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 @@ fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) {
}
}
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
}
@@ -2,7 +2,7 @@
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 @@ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result {
}
// 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 @@ fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> Self::Result {
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 {
@@ -0,0 +1,9 @@
#![feature(generic_arg_infer, closure_lifetime_binder)]
struct Foo<const N: usize>([u32; N]);
fn main() {
let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0[0] };
//~^ ERROR: implicit types in closure signatures are forbidden when `for<...>` is present
c(&Foo([1_u32; 1]));
}
@@ -0,0 +1,10 @@
error: implicit types in closure signatures are forbidden when `for<...>` is present
--> $DIR/forbid_ambig_const_infers.rs:6:33
|
LL | let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0[0] };
| ------- ^
| |
| `for<...>` is here
error: aborting due to 1 previous error
@@ -0,0 +1,9 @@
#![feature(generic_arg_infer, closure_lifetime_binder)]
struct Foo<T>(T);
fn main() {
let c = for<'a> |b: &'a Foo<_>| -> u32 { b.0 };
//~^ ERROR: implicit types in closure signatures are forbidden when `for<...>` is present
c(&Foo(1_u32));
}

Some files were not shown because too many files have changed in this diff Show More