Skip to content

Commit db19e2b

Browse files
committed
fix simplify_type
1 parent 00755e4 commit db19e2b

File tree

9 files changed

+63
-86
lines changed

9 files changed

+63
-86
lines changed

compiler/rustc_metadata/src/rmeta/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18321832
let simplified_self_ty = fast_reject::simplify_type(
18331833
self.tcx,
18341834
trait_ref.self_ty(),
1835-
TreatParams::AsPlaceholders,
1835+
TreatParams::AsInfer,
18361836
);
18371837

18381838
fx_hash_map

compiler/rustc_middle/src/ty/fast_reject.rs

+43-60
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
use crate::mir::Mutability;
2-
use crate::ty::{self, Ty, TyCtxt};
3-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2+
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
43
use rustc_hir::def_id::DefId;
5-
use rustc_query_system::ich::StableHashingContext;
64
use std::fmt::Debug;
75
use std::hash::Hash;
8-
use std::mem;
96

107
use self::SimplifiedTypeGen::*;
118

@@ -17,7 +14,7 @@ pub type SimplifiedType = SimplifiedTypeGen<DefId>;
1714
/// because we sometimes need to use SimplifiedTypeGen values as stable sorting
1815
/// keys (in which case we use a DefPathHash as id-type) but in the general case
1916
/// the non-stable but fast to construct DefId-version is the better choice.
20-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
17+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
2118
pub enum SimplifiedTypeGen<D>
2219
where
2320
D: Copy + Debug + Eq,
@@ -45,34 +42,49 @@ where
4542
GeneratorWitnessSimplifiedType(usize),
4643
OpaqueSimplifiedType(D),
4744
FunctionSimplifiedType(usize),
48-
ParameterSimplifiedType,
45+
PlaceholderSimplifiedType,
4946
}
5047

48+
/// Generic parameters are pretty much just bound variables, e.g.
49+
/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as
50+
/// `for<'a, T> fn(&'a T) -> u32`.
51+
///
52+
/// Typecheck of `foo` has to succeed for all possible generic arguments, so
53+
/// during typeck, we have to treat its generic parameters as if they
54+
/// were placeholders.
55+
///
56+
/// But when calling `foo` we only have to provide a specific generic argument.
57+
/// In that case the generic parameters are instantiated with inference variables.
58+
/// As we use `simplify_type` before that instantiation happens, we just treat
59+
/// generic parameters as if they were inference variables in that case.
5160
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
5261
pub enum TreatParams {
53-
/// Treat parameters as bound types in the given environment.
62+
/// Treat parameters as placeholders in the given environment.
5463
///
55-
/// For this to be correct the input has to be fully normalized
56-
/// in its param env as it may otherwise cause us to ignore
57-
/// potentially applying impls.
58-
AsBoundTypes,
59-
AsPlaceholders,
64+
/// Note that this also causes us to treat projections as if they were
65+
/// placeholders. This is only correct if the given projection cannot
66+
/// be normalized in the current context. Even if normalization fails,
67+
/// it may still succeed later if the projection contains any inference
68+
/// variables.
69+
AsPlaceholder,
70+
AsInfer,
6071
}
6172

6273
/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
6374
///
6475
/// The idea is to get something simple that we can use to quickly decide if two types could unify,
65-
/// for example during method lookup.
76+
/// for example during method lookup. If this function returns `Some(x)` it can only unify with
77+
/// types for which this method returns either `Some(x)` as well or `None`.
6678
///
6779
/// A special case here are parameters and projections, which are only injective
68-
/// if they are treated as bound types.
80+
/// if they are treated as placeholders.
6981
///
7082
/// For example when storing impls based on their simplified self type, we treat
71-
/// generic parameters as placeholders. We must not simplify them here,
83+
/// generic parameters as if they were inference variables. We must not simplify them here,
7284
/// as they can unify with any other type.
7385
///
74-
/// With projections we have to be even more careful, as even when treating them as bound types
75-
/// this is still only correct if they are fully normalized.
86+
/// With projections we have to be even more careful, as treating them as placeholders
87+
/// is only correct if they are fully normalized.
7688
///
7789
/// ¹ meaning that if the outermost layers are different, then the whole types are also different.
7890
pub fn simplify_type<'tcx>(
@@ -104,20 +116,25 @@ pub fn simplify_type<'tcx>(
104116
ty::Never => Some(NeverSimplifiedType),
105117
ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())),
106118
ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
107-
ty::Param(_) | ty::Projection(_) => match treat_params {
108-
// When treated as bound types, projections don't unify with
109-
// anything as long as they are fully normalized.
119+
ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
120+
ty::Param(_) => match treat_params {
121+
TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
122+
TreatParams::AsInfer => None,
123+
},
124+
ty::Projection(_) => match treat_params {
125+
// When treating `ty::Param` as a placeholder, projections also
126+
// don't unify with anything else as long as they are fully normalized.
110127
//
111128
// We will have to be careful with lazy normalization here.
112-
TreatParams::AsBoundTypes => {
113-
debug!("treating `{}` as a bound type", ty);
114-
Some(ParameterSimplifiedType)
129+
TreatParams::AsPlaceholder if !ty.has_infer_types_or_consts() => {
130+
debug!("treating `{}` as a placeholder", ty);
131+
Some(PlaceholderSimplifiedType)
115132
}
116-
TreatParams::AsPlaceholders => None,
133+
TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
117134
},
118135
ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
119136
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
120-
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
137+
ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
121138
}
122139
}
123140

@@ -161,41 +178,7 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
161178
GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
162179
OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)),
163180
FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
164-
ParameterSimplifiedType => ParameterSimplifiedType,
165-
}
166-
}
167-
}
168-
169-
impl<'a, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D>
170-
where
171-
D: Copy + Debug + Eq + HashStable<StableHashingContext<'a>>,
172-
{
173-
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
174-
mem::discriminant(self).hash_stable(hcx, hasher);
175-
match *self {
176-
BoolSimplifiedType
177-
| CharSimplifiedType
178-
| StrSimplifiedType
179-
| ArraySimplifiedType
180-
| SliceSimplifiedType
181-
| NeverSimplifiedType
182-
| ParameterSimplifiedType
183-
| MarkerTraitObjectSimplifiedType => {
184-
// nothing to do
185-
}
186-
RefSimplifiedType(m) | PtrSimplifiedType(m) => m.hash_stable(hcx, hasher),
187-
IntSimplifiedType(t) => t.hash_stable(hcx, hasher),
188-
UintSimplifiedType(t) => t.hash_stable(hcx, hasher),
189-
FloatSimplifiedType(t) => t.hash_stable(hcx, hasher),
190-
AdtSimplifiedType(d) => d.hash_stable(hcx, hasher),
191-
TupleSimplifiedType(n) => n.hash_stable(hcx, hasher),
192-
TraitSimplifiedType(d) => d.hash_stable(hcx, hasher),
193-
ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher),
194-
GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher),
195-
GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher),
196-
OpaqueSimplifiedType(d) => d.hash_stable(hcx, hasher),
197-
FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher),
198-
ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher),
181+
PlaceholderSimplifiedType => PlaceholderSimplifiedType,
199182
}
200183
}
201184
}

compiler/rustc_middle/src/ty/trait_def.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ impl<'tcx> TyCtxt<'tcx> {
143143
self_ty: Ty<'tcx>,
144144
) -> impl Iterator<Item = DefId> + 'tcx {
145145
let impls = self.trait_impls_of(def_id);
146-
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholders) {
146+
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
147147
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
148148
return impls.iter().copied();
149149
}
@@ -173,14 +173,14 @@ impl<'tcx> TyCtxt<'tcx> {
173173
}
174174
}
175175

176-
// Note that we're using `TreatParams::AsBoundTypes` to query `non_blanket_impls` while using
177-
// `TreatParams::AsPlaceholders` while actually adding them.
176+
// Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using
177+
// `TreatParams::AsInfer` while actually adding them.
178178
//
179179
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
180180
// whose outer level is not a parameter or projection. Especially for things like
181181
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
182182
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
183-
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsBoundTypes) {
183+
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) {
184184
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
185185
for &impl_def_id in impls {
186186
if let result @ Some(_) = f(impl_def_id) {
@@ -240,7 +240,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
240240
}
241241

242242
if let Some(simplified_self_ty) =
243-
fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsPlaceholders)
243+
fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer)
244244
{
245245
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
246246
} else {

compiler/rustc_trait_selection/src/traits/coherence.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ where
8888
impl2_ref.iter().flat_map(|tref| tref.substs.types()),
8989
)
9090
.any(|(ty1, ty2)| {
91-
let t1 = fast_reject::simplify_type(tcx, ty1, TreatParams::AsPlaceholders);
92-
let t2 = fast_reject::simplify_type(tcx, ty2, TreatParams::AsPlaceholders);
91+
let t1 = fast_reject::simplify_type(tcx, ty1, TreatParams::AsInfer);
92+
let t2 = fast_reject::simplify_type(tcx, ty2, TreatParams::AsInfer);
9393

9494
if let (Some(t1), Some(t2)) = (t1, t2) {
9595
// Simplified successfully

compiler/rustc_trait_selection/src/traits/select/mod.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -2142,13 +2142,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21422142
let simplified_obligation_ty = fast_reject::simplify_type(
21432143
self.tcx(),
21442144
obligation_ty,
2145-
TreatParams::AsBoundTypes,
2146-
);
2147-
let simplified_impl_ty = fast_reject::simplify_type(
2148-
self.tcx(),
2149-
impl_ty,
2150-
TreatParams::AsPlaceholders,
2145+
TreatParams::AsPlaceholder,
21512146
);
2147+
let simplified_impl_ty =
2148+
fast_reject::simplify_type(self.tcx(), impl_ty, TreatParams::AsInfer);
21522149

21532150
simplified_obligation_ty.is_some()
21542151
&& simplified_impl_ty.is_some()

compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ impl ChildrenExt<'_> for Children {
4949
/// Insert an impl into this set of children without comparing to any existing impls.
5050
fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
5151
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
52-
if let Some(st) =
53-
fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders)
52+
if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
5453
{
5554
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
5655
self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
@@ -66,8 +65,7 @@ impl ChildrenExt<'_> for Children {
6665
fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
6766
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
6867
let vec: &mut Vec<DefId>;
69-
if let Some(st) =
70-
fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders)
68+
if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
7169
{
7270
debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
7371
vec = self.non_blanket_impls.get_mut(&st).unwrap();
@@ -316,8 +314,7 @@ impl GraphExt for Graph {
316314

317315
let mut parent = trait_def_id;
318316
let mut last_lint = None;
319-
let simplified =
320-
fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders);
317+
let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer);
321318

322319
// Descend the specialization tree, where `parent` is the current parent node.
323320
loop {

compiler/rustc_typeck/src/check/method/probe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
681681
}
682682

683683
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
684-
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsPlaceholders) else {
684+
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else {
685685
bug!("unexpected incoherent type: {:?}", self_ty)
686686
};
687687
for &impl_def_id in self.tcx.incoherent_impls(simp) {

compiler/rustc_typeck/src/check/method/suggest.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12361236
.into_iter()
12371237
.any(|info| self.associated_value(info.def_id, item_name).is_some());
12381238
let found_assoc = |ty: Ty<'tcx>| {
1239-
simplify_type(tcx, ty, TreatParams::AsPlaceholders)
1239+
simplify_type(tcx, ty, TreatParams::AsInfer)
12401240
.and_then(|simp| {
12411241
tcx.incoherent_impls(simp)
12421242
.iter()
@@ -1956,7 +1956,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19561956
// cases where a positive bound implies a negative impl.
19571957
(candidates, Vec::new())
19581958
} else if let Some(simp_rcvr_ty) =
1959-
simplify_type(self.tcx, rcvr_ty, TreatParams::AsBoundTypes)
1959+
simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
19601960
{
19611961
let mut potential_candidates = Vec::new();
19621962
let mut explicitly_negative = Vec::new();
@@ -1971,7 +1971,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19711971
.any(|imp_did| {
19721972
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
19731973
let imp_simp =
1974-
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsBoundTypes);
1974+
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
19751975
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
19761976
})
19771977
{

compiler/rustc_typeck/src/coherence/inherent_impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl<'tcx> InherentCollect<'tcx> {
104104
}
105105
}
106106

107-
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsPlaceholders) {
107+
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
108108
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
109109
} else {
110110
bug!("unexpected self type: {:?}", self_ty);
@@ -169,7 +169,7 @@ impl<'tcx> InherentCollect<'tcx> {
169169
}
170170
}
171171

172-
if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsPlaceholders) {
172+
if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsInfer) {
173173
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
174174
} else {
175175
bug!("unexpected primitive type: {:?}", ty);

0 commit comments

Comments
 (0)