]> git.lizzy.rs Git - rust.git/blobdiff - clippy_utils/src/ty.rs
Merge remote-tracking branch 'upstream/master' into rustup
[rust.git] / clippy_utils / src / ty.rs
index 09967f317f891e4e05153c895db4cf8cc605a4d7..bfb2d472a393cf0525955de8f38dce24e0f270b2 100644 (file)
@@ -9,20 +9,23 @@
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{
+    type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
+    TyCtxtInferExt,
+};
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
-    self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, GenericParamDefKind, IntTy, List, ParamEnv,
-    Predicate, PredicateKind, ProjectionTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr,
+    self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
+    ProjectionTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
+    VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Size, VariantIdx};
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::query::normalize::AtExt;
+use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use std::iter;
 
 use crate::{match_def_path, path_res, paths};
@@ -81,7 +84,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                     match predicate.kind().skip_binder() {
                         // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                         // and check substituions to find `U`.
-                        ty::PredicateKind::Trait(trait_predicate) => {
+                        ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
                             if trait_predicate
                                 .trait_ref
                                 .substs
@@ -94,7 +97,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         },
                         // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
                         // so we check the term for `U`.
-                        ty::PredicateKind::Projection(projection_predicate) => {
+                        ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
                             if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
                                 if contains_ty_adt_constructor_opaque(cx, ty, needle) {
                                     return true;
@@ -117,24 +120,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
 pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     cx.tcx
         .get_diagnostic_item(sym::Iterator)
-        .and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item"))
-}
-
-/// Returns the associated type `name` for `ty` as an implementation of `trait_id`.
-/// Do not invoke without first verifying that the type implements the trait.
-pub fn get_associated_type<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: Ty<'tcx>,
-    trait_id: DefId,
-    name: &str,
-) -> Option<Ty<'tcx>> {
-    cx.tcx
-        .associated_items(trait_id)
-        .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
-        .and_then(|assoc| {
-            let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[]));
-            cx.tcx.try_normalize_erasing_regions(cx.param_env, proj).ok()
-        })
+        .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item"))
 }
 
 /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
@@ -206,7 +192,13 @@ pub fn implements_trait<'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env(cx.tcx, cx.param_env, ty, trait_id, ty_params)
+    implements_trait_with_env(
+        cx.tcx,
+        cx.param_env,
+        ty,
+        trait_id,
+        ty_params.iter().map(|&arg| Some(arg)),
+    )
 }
 
 /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -215,7 +207,7 @@ pub fn implements_trait_with_env<'tcx>(
     param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: &[GenericArg<'tcx>],
+    ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
 ) -> bool {
     // Clippy shouldn't have infer types
     assert!(!ty.needs_infer());
@@ -224,10 +216,18 @@ pub fn implements_trait_with_env<'tcx>(
     if ty.has_escaping_bound_vars() {
         return false;
     }
-    let ty_params = tcx.mk_substs(ty_params.iter());
     let infcx = tcx.infer_ctxt().build();
+    let orig = TypeVariableOrigin {
+        kind: TypeVariableOriginKind::MiscVariable,
+        span: DUMMY_SP,
+    };
+    let ty_params = tcx.mk_substs(
+        ty_params
+            .into_iter()
+            .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
+    );
     infcx
-        .type_implements_trait(trait_id, ty, ty_params, param_env)
+        .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
         .must_apply_modulo_regions()
 }
 
@@ -252,7 +252,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
-                if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
+                if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
                     }
@@ -296,7 +296,7 @@ fn is_normalizable_helper<'tcx>(
     cache.insert(ty, false);
     let infcx = cx.tcx.infer_ctxt().build();
     let cause = rustc_middle::traits::ObligationCause::dummy();
-    let result = if infcx.at(&cause, param_env).normalize(ty).is_ok() {
+    let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
         match ty.kind() {
             ty::Adt(def, substs) => def.variants().iter().all(|variant| {
                 variant
@@ -671,7 +671,7 @@ fn sig_from_bounds<'tcx>(
 
     for pred in predicates {
         match pred.kind().skip_binder() {
-            PredicateKind::Trait(p)
+            PredicateKind::Clause(ty::Clause::Trait(p))
                 if (lang_items.fn_trait() == Some(p.def_id())
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id()))
@@ -684,7 +684,7 @@ fn sig_from_bounds<'tcx>(
                 }
                 inputs = Some(i);
             },
-            PredicateKind::Projection(p)
+            PredicateKind::Clause(ty::Clause::Projection(p))
                 if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
                     && p.projection_ty.self_ty() == ty =>
             {
@@ -712,7 +712,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
         .subst_iter_copied(cx.tcx, ty.substs)
     {
         match pred.kind().skip_binder() {
-            PredicateKind::Trait(p)
+            PredicateKind::Clause(ty::Clause::Trait(p))
                 if (lang_items.fn_trait() == Some(p.def_id())
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id())) =>
@@ -725,7 +725,9 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
                 }
                 inputs = Some(i);
             },
-            PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
+            PredicateKind::Clause(ty::Clause::Projection(p))
+                if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() =>
+            {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
@@ -900,7 +902,7 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
     predicates
         .iter()
         .try_fold(false, |found, p| {
-            if let PredicateKind::Trait(p) = p.kind().skip_binder()
+            if let PredicateKind::Clause(ty::Clause::Trait(p)) = p.kind().skip_binder()
             && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
             && ty.index == self_ty.index
         {
@@ -1010,7 +1012,7 @@ fn helper<'tcx>(
                     the given arguments are: `{substs:#?}`",
                 assoc_item.def_id,
                 substs.len(),
-                params.map(GenericParamDefKind::descr).collect::<Vec<_>>(),
+                params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
             );
 
             if let Some((idx, (param, arg))) = params
@@ -1020,9 +1022,9 @@ fn helper<'tcx>(
                 .find(|(_, (param, arg))| {
                     !matches!(
                         (param, arg),
-                        (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
-                            | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
-                            | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
+                        (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
+                            | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
+                            | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
                     )
                 })
             {
@@ -1032,7 +1034,7 @@ fn helper<'tcx>(
                         note: the expected parameters are {:#?}\n\
                         the given arguments are {substs:#?}",
                     param.descr(),
-                    params.map(GenericParamDefKind::descr).collect::<Vec<_>>()
+                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
                 );
             }
         }