-
Notifications
You must be signed in to change notification settings - Fork 13.4k
extend simplify_type
#86986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
extend simplify_type
#86986
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(D), | ||
StrSimplifiedType, | ||
ArraySimplifiedType, | ||
PtrSimplifiedType, | ||
SliceSimplifiedType, | ||
RefSimplifiedType(Mutability), | ||
PtrSimplifiedType(Mutability), | ||
NeverSimplifiedType, | ||
TupleSimplifiedType(usize), | ||
/// A trait object, all of whose components are markers | ||
|
@@ -42,22 +46,48 @@ where | |
OpaqueSimplifiedType(D), | ||
FunctionSimplifiedType(usize), | ||
ParameterSimplifiedType, | ||
ForeignSimplifiedType(DefId), | ||
} | ||
|
||
/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc. | ||
/// The idea is to get something simple that we can use to quickly decide if two types could unify | ||
/// during method lookup. | ||
#[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 only returning the outermost injective¹ layer, if one exists. | ||
/// | ||
/// The idea is to get something simple that we can use to quickly decide if two types could unify, | ||
/// for example during method lookup. | ||
/// | ||
/// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This | ||
/// is useful when those type parameters would be instantiated with fresh type variables, since | ||
/// then we can't say much about whether two types would unify. Put another way, | ||
/// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they | ||
/// are to be considered bound. | ||
/// A special case here are parameters and projections. Projections can be normalized to | ||
/// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though | ||
/// their outermost layer is different while parameters like `T` of impls are later replaced | ||
/// with an inference variable, which then also allows unification with other types. | ||
/// | ||
/// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections², | ||
/// the reasoning for this can be seen at the places doing this. | ||
/// | ||
/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best | ||
/// way to skip some unhelpful suggestions. | ||
/// | ||
/// ¹ meaning that if two outermost layers are different, then the whole types are also different. | ||
/// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during | ||
/// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even | ||
/// though `_` can be inferred to a concrete type later at which point a concrete impl | ||
/// could actually apply. After experimenting for about an hour I wasn't able to cause any issues | ||
/// this way so I am not going to change this until we actually find an issue as I am really | ||
/// interesting in getting an actual test for this. | ||
Comment on lines
+80
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nikomatsakis does this comment make sense to you? I hoped to trigger it by using something like the following, but wasn't able to make much progress. We either normalize the projection because it is already concrete enough or fail for some different reason. Not sure if this is actually exploitable if it even is an issue. trait Id {
type Assoc;
}
impl<T> Id for T {
type Assoc = Self;
}
trait Bar<T> {
type Assoc;
fn bar(self) -> Self::Assoc;
}
impl Bar<u32> for i32 {
type Assoc = i32;
fn bar(self) -> Self::Assoc {
1
}
}
fn main() {
let mut x = <<_ as Id>::Assoc>::default();
x = <_ as Bar<u32>>::bar(x);
} |
||
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 +97,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 +125,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 +155,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(map(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 +171,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 +186,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), | ||
|
Uh oh!
There was an error while loading. Please reload this page.