about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2021-05-07 20:00:02 +0200
committerlcnr <rust@lcnr.de>2021-12-14 13:32:42 +0100
commitdcd716fee2303c93a0bf1ba68e667c9bc4bf3558 (patch)
tree06fbf4248ed530c10b97b195276180bd510e9a24 /compiler
parent83b32f27fc6c34b0b411f47be31ab4ae07eafed4 (diff)
downloadrust-dcd716fee2303c93a0bf1ba68e667c9bc4bf3558.tar.gz
rust-dcd716fee2303c93a0bf1ba68e667c9bc4bf3558.zip
extend `simplify_type`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs11
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs52
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs23
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs13
8 files changed, 117 insertions, 40 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 94e7376ddb2..3154859bc65 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -26,6 +26,7 @@ use rustc_middle::mir::interpret;
 use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
@@ -2033,15 +2034,19 @@ impl EncodeContext<'a, 'tcx> {
 
 struct ImplVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    impls: FxHashMap<DefId, Vec<(DefIndex, Option<ty::fast_reject::SimplifiedType>)>>,
+    impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>,
 }
 
 impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::Impl { .. } = item.kind {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
-                let simplified_self_ty =
-                    ty::fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), false);
+                let simplified_self_ty = fast_reject::simplify_type(
+                    self.tcx,
+                    trait_ref.self_ty(),
+                    SimplifyParams::No,
+                    StripReferences::No,
+                );
 
                 self.impls
                     .entry(trait_ref.def_id)
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 11ee942b83e..f49472afb1c 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,3 +1,4 @@
+use crate::mir::Mutability;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
@@ -27,9 +28,12 @@ where
     UintSimplifiedType(ty::UintTy),
     FloatSimplifiedType(ty::FloatTy),
     AdtSimplifiedType(D),
+    ForeignSimplifiedType(DefId),
     StrSimplifiedType,
     ArraySimplifiedType,
-    PtrSimplifiedType,
+    SliceSimplifiedType,
+    RefSimplifiedType(Mutability),
+    PtrSimplifiedType(Mutability),
     NeverSimplifiedType,
     TupleSimplifiedType(usize),
     /// A trait object, all of whose components are markers
@@ -42,7 +46,18 @@ where
     OpaqueSimplifiedType(D),
     FunctionSimplifiedType(usize),
     ParameterSimplifiedType,
-    ForeignSimplifiedType(DefId),
+}
+
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum SimplifyParams {
+    Yes,
+    No,
+}
+
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum StripReferences {
+    Yes,
+    No,
 }
 
 /// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc.
@@ -57,7 +72,8 @@ where
 pub fn simplify_type(
     tcx: TyCtxt<'_>,
     ty: Ty<'_>,
-    can_simplify_params: bool,
+    can_simplify_params: SimplifyParams,
+    strip_references: StripReferences,
 ) -> Option<SimplifiedType> {
     match *ty.kind() {
         ty::Bool => Some(BoolSimplifiedType),
@@ -67,19 +83,24 @@ pub fn simplify_type(
         ty::Float(float_type) => Some(FloatSimplifiedType(float_type)),
         ty::Adt(def, _) => Some(AdtSimplifiedType(def.did)),
         ty::Str => Some(StrSimplifiedType),
-        ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
-        ty::RawPtr(_) => Some(PtrSimplifiedType),
+        ty::Array(..) => Some(ArraySimplifiedType),
+        ty::Slice(..) => Some(SliceSimplifiedType),
+        ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)),
         ty::Dynamic(ref trait_info, ..) => match trait_info.principal_def_id() {
             Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
                 Some(TraitSimplifiedType(principal_def_id))
             }
             _ => Some(MarkerTraitObjectSimplifiedType),
         },
-        ty::Ref(_, ty, _) => {
-            // since we introduce auto-refs during method lookup, we
-            // just treat &T and T as equivalent from the point of
-            // view of possibly unifying
-            simplify_type(tcx, ty, can_simplify_params)
+        ty::Ref(_, ty, mutbl) => {
+            if strip_references == StripReferences::Yes {
+                // For diagnostics, when recommending similar impls we want to
+                // recommend impls even when there is a reference mismatch,
+                // so we treat &T and T equivalently in that case.
+                simplify_type(tcx, ty, can_simplify_params, strip_references)
+            } else {
+                Some(RefSimplifiedType(mutbl))
+            }
         }
         ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
         ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
@@ -90,7 +111,7 @@ pub fn simplify_type(
         ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())),
         ty::FnPtr(ref f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
         ty::Projection(_) | ty::Param(_) => {
-            if can_simplify_params {
+            if can_simplify_params == SimplifyParams::Yes {
                 // In normalized types, projections don't unify with
                 // anything. when lazy normalization happens, this
                 // will change. It would still be nice to have a way
@@ -120,9 +141,12 @@ impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
             UintSimplifiedType(t) => UintSimplifiedType(t),
             FloatSimplifiedType(t) => FloatSimplifiedType(t),
             AdtSimplifiedType(d) => AdtSimplifiedType(map(d)),
+            ForeignSimplifiedType(d) => ForeignSimplifiedType(d),
             StrSimplifiedType => StrSimplifiedType,
             ArraySimplifiedType => ArraySimplifiedType,
-            PtrSimplifiedType => PtrSimplifiedType,
+            SliceSimplifiedType => SliceSimplifiedType,
+            RefSimplifiedType(m) => RefSimplifiedType(m),
+            PtrSimplifiedType(m) => PtrSimplifiedType(m),
             NeverSimplifiedType => NeverSimplifiedType,
             MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
             TupleSimplifiedType(n) => TupleSimplifiedType(n),
@@ -133,7 +157,6 @@ impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
             OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)),
             FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
             ParameterSimplifiedType => ParameterSimplifiedType,
-            ForeignSimplifiedType(d) => ForeignSimplifiedType(d),
         }
     }
 }
@@ -149,12 +172,13 @@ where
             | CharSimplifiedType
             | StrSimplifiedType
             | ArraySimplifiedType
-            | PtrSimplifiedType
+            | SliceSimplifiedType
             | NeverSimplifiedType
             | ParameterSimplifiedType
             | MarkerTraitObjectSimplifiedType => {
                 // nothing to do
             }
+            RefSimplifiedType(m) | PtrSimplifiedType(m) => m.hash_stable(hcx, hasher),
             IntSimplifiedType(t) => t.hash_stable(hcx, hasher),
             UintSimplifiedType(t) => t.hash_stable(hcx, hasher),
             FloatSimplifiedType(t) => t.hash_stable(hcx, hasher),
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 25a310b12db..4a415b7a228 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,5 +1,5 @@
 use crate::traits::specialization_graph;
-use crate::ty::fast_reject;
+use crate::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ty, TyCtxt};
 use rustc_hir as hir;
@@ -179,7 +179,9 @@ impl<'tcx> TyCtxt<'tcx> {
         // blanket and non-blanket impls, and compare them separately.
         //
         // I think we'll cross that bridge when we get to it.
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) {
+        if let Some(simp) =
+            fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No)
+        {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
                     if let result @ Some(_) = f(impl_def_id) {
@@ -238,7 +240,9 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
             continue;
         }
 
-        if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) {
+        if let Some(simplified_self_ty) =
+            fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No, StripReferences::No)
+        {
             impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
         } else {
             impls.blanket_impls.push(impl_def_id);
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index aec9da9f8d4..5fac2e55b1d 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -12,9 +12,10 @@ use crate::traits::{
     self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
 };
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, fast_reject, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::iter;
@@ -82,12 +83,11 @@ where
         impl2_ref.iter().flat_map(|tref| tref.substs.types()),
     )
     .any(|(ty1, ty2)| {
-        let t1 = fast_reject::simplify_type(tcx, ty1, false);
-        let t2 = fast_reject::simplify_type(tcx, ty2, false);
+        let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
+        let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
         if let (Some(t1), Some(t2)) = (t1, t2) {
             // Simplified successfully
-            // Types cannot unify if they differ in their reference mutability or simplify to different types
-            t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability()
+            t1 != t2
         } else {
             // Types might unify
             false
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 310eecc6e85..00b469c686a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -21,9 +21,10 @@ use rustc_hir::Item;
 use rustc_hir::Node;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
-    self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
+    self, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
     TypeFoldable,
 };
 use rustc_session::DiagnosticMessageId;
@@ -1439,14 +1440,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Vec<ty::TraitRef<'tcx>> {
-        let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true);
+        let simp = fast_reject::simplify_type(
+            self.tcx,
+            trait_ref.skip_binder().self_ty(),
+            SimplifyParams::Yes,
+            StripReferences::Yes,
+        );
         let all_impls = self.tcx.all_impls(trait_ref.def_id());
 
         match simp {
             Some(simp) => all_impls
                 .filter_map(|def_id| {
                     let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                    let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true);
+                    let imp_simp = fast_reject::simplify_type(
+                        self.tcx,
+                        imp.self_ty(),
+                        SimplifyParams::Yes,
+                        StripReferences::Yes,
+                    );
                     if let Some(imp_simp) = imp_simp {
                         if simp != imp_simp {
                             return None;
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2b120e855eb..607deb8f908 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -35,7 +35,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@@ -2089,10 +2089,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             |(obligation_arg, impl_arg)| {
                 match (obligation_arg.unpack(), impl_arg.unpack()) {
                     (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => {
-                        let simplified_obligation_ty =
-                            fast_reject::simplify_type(self.tcx(), obligation_ty, true);
-                        let simplified_impl_ty =
-                            fast_reject::simplify_type(self.tcx(), impl_ty, false);
+                        // Note, we simplify parameters for the obligation but not the
+                        // impl so that we do not reject a blanket impl but do reject
+                        // more concrete impls if we're searching for `T: Trait`.
+                        let simplified_obligation_ty = fast_reject::simplify_type(
+                            self.tcx(),
+                            obligation_ty,
+                            SimplifyParams::Yes,
+                            StripReferences::No,
+                        );
+                        let simplified_impl_ty = fast_reject::simplify_type(
+                            self.tcx(),
+                            impl_ty,
+                            SimplifyParams::No,
+                            StripReferences::No,
+                        );
 
                         simplified_obligation_ty.is_some()
                             && simplified_impl_ty.is_some()
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index ec7dcd4a419..2f9d2c47b01 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -2,7 +2,7 @@ use super::OverlapError;
 
 use crate::traits;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 
@@ -48,7 +48,12 @@ impl ChildrenExt for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
+        if let Some(st) = fast_reject::simplify_type(
+            tcx,
+            trait_ref.self_ty(),
+            SimplifyParams::No,
+            StripReferences::No,
+        ) {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
             self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
         } else {
@@ -63,7 +68,12 @@ impl ChildrenExt for Children {
     fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let vec: &mut Vec<DefId>;
-        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
+        if let Some(st) = fast_reject::simplify_type(
+            tcx,
+            trait_ref.self_ty(),
+            SimplifyParams::No,
+            StripReferences::No,
+        ) {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
             vec = self.non_blanket_impls.get_mut(&st).unwrap();
         } else {
@@ -306,7 +316,12 @@ impl GraphExt for Graph {
 
         let mut parent = trait_def_id;
         let mut last_lint = None;
-        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);
+        let simplified = fast_reject::simplify_type(
+            tcx,
+            trait_ref.self_ty(),
+            SimplifyParams::No,
+            StripReferences::No,
+        );
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 45b8e13d328..41c652616ca 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::fast_reject::simplify_type;
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
 use rustc_middle::ty::print::with_crate_prefix;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
@@ -1703,7 +1703,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // FIXME: Even though negative bounds are not implemented, we could maybe handle
                 // cases where a positive bound implies a negative impl.
                 (candidates, Vec::new())
-            } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, true) {
+            } else if let Some(simp_rcvr_ty) =
+                simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes, StripReferences::No)
+            {
                 let mut potential_candidates = Vec::new();
                 let mut explicitly_negative = Vec::new();
                 for candidate in candidates {
@@ -1716,7 +1718,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         })
                         .any(|imp_did| {
                             let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
-                            let imp_simp = simplify_type(self.tcx, imp.self_ty(), true);
+                            let imp_simp = simplify_type(
+                                self.tcx,
+                                imp.self_ty(),
+                                SimplifyParams::Yes,
+                                StripReferences::No,
+                            );
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
                         })
                     {