Skip to content

Commit af68005

Browse files
committed
Improve fast rejection.
In particular, for `bitmaps-3.1.0` which does a huge number of comparisons between `BitsImpl<M>` and `BitsImpl<N>` where `M` and `N` are const integers.
1 parent b2eed72 commit af68005

File tree

1 file changed

+118
-15
lines changed
  • compiler/rustc_trait_selection/src/traits/select

1 file changed

+118
-15
lines changed

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

+118-15
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
3333
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
3434
use rustc_middle::mir::interpret::ErrorHandled;
3535
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
36-
use rustc_middle::ty::fast_reject::{self, TreatParams};
3736
use rustc_middle::ty::fold::BottomUpFolder;
3837
use rustc_middle::ty::print::with_no_trimmed_paths;
3938
use rustc_middle::ty::relate::TypeRelation;
@@ -214,6 +213,122 @@ enum BuiltinImplConditions<'tcx> {
214213
Ambiguous,
215214
}
216215

216+
fn tys_may_be_equivalent<'tcx>(oblig_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
217+
let k = impl_ty.kind();
218+
219+
// First, look for obvious equivalences, e.g. the types are equal. The most
220+
// common case is to find such an equivalence trivially, e.g. `ty::Bool`
221+
// and `ty::Bool`.
222+
let mut maybe_equiv = match oblig_ty.kind() {
223+
ty::Bool => matches!(k, ty::Bool),
224+
ty::Char => matches!(k, ty::Char),
225+
ty::Int(ity) => matches!(k, ty::Int(ity2) if ity == ity2),
226+
ty::Uint(uty) => matches!(k, ty::Uint(uty2) if uty == uty2),
227+
ty::Float(fty) => matches!(k, ty::Float(fty2) if fty == fty2),
228+
ty::Adt(def_id, substs1) => match k {
229+
ty::Adt(def_id2, substs2) => {
230+
def_id == def_id2 && {
231+
// Check for cases like `Foo<3>` vs `Foo<4>`, which are hot
232+
// in crates such as `bitmaps` and `nalgebra`.
233+
let differ_by_single_const_arg = if
234+
substs1.len() == 1
235+
&& substs2.len() == 1
236+
&& let ty::subst::GenericArgKind::Const(c1) = substs1[0].unpack()
237+
&& let ty::subst::GenericArgKind::Const(c2) = substs2[0].unpack()
238+
&& let Some(s1) = c1.val().try_to_scalar_int()
239+
&& let Some(s2) = c2.val().try_to_scalar_int()
240+
&& s1 != s2
241+
{
242+
true
243+
} else {
244+
false
245+
};
246+
!differ_by_single_const_arg
247+
}
248+
}
249+
_ => false,
250+
},
251+
ty::Str => matches!(k, ty::Str),
252+
ty::Array(..) => matches!(k, ty::Array(..)),
253+
ty::Slice(..) => matches!(k, ty::Slice(..)),
254+
ty::RawPtr(ptr) => matches!(k, ty::RawPtr(ptr2) if ptr.mutbl == ptr2.mutbl),
255+
ty::Dynamic(trait_info, ..) => {
256+
matches!(k, ty::Dynamic(trait_info2, ..) if
257+
trait_info.principal_def_id() == trait_info2.principal_def_id()
258+
)
259+
}
260+
ty::Ref(_, _, mutbl) => matches!(k, ty::Ref(_, _, mutbl2) if mutbl == mutbl2),
261+
ty::FnDef(def_id, _) => matches!(k, ty::FnDef(def_id2, _) if def_id == def_id2),
262+
ty::Closure(def_id, _) => matches!(k, ty::Closure(def_id2, _) if def_id == def_id2),
263+
ty::Generator(def_id, ..) => {
264+
matches!(k, ty::Generator(def_id2, ..) if def_id == def_id2)
265+
}
266+
ty::Never => matches!(k, ty::Never),
267+
ty::Tuple(tys) => matches!(k, ty::Tuple(tys2) if tys.len() == tys2.len()),
268+
ty::FnPtr(tys) => {
269+
matches!(
270+
k,
271+
ty::FnPtr(tys2)
272+
if tys.skip_binder().inputs().len() == tys2.skip_binder().inputs().len()
273+
)
274+
}
275+
ty::Opaque(def_id, _) => matches!(k, ty::Opaque(def_id2, _) if def_id == def_id2),
276+
ty::Foreign(def_id) => matches!(k, ty::Foreign(def_id2) if def_id == def_id2),
277+
ty::Param(_) => {
278+
// Note, we simplify parameters for the obligation but not the impl
279+
// so that we do not reject a blanket impl but do reject more
280+
// concrete impls if we're searching for `T: Trait`.
281+
matches!(k, ty::Placeholder(..))
282+
}
283+
ty::Projection(_) => {
284+
// When treating `ty::Param` as a placeholder, projections also
285+
// don't unify with anything else as long as they are fully normalized.
286+
//
287+
// We will have to be careful with lazy normalization here.
288+
oblig_ty.has_infer_types_or_consts() || matches!(k, ty::Placeholder(..))
289+
}
290+
ty::Infer(_) => true,
291+
292+
ty::GeneratorWitness(..) | ty::Placeholder(..) | ty::Bound(..) | ty::Error(_) => {
293+
unreachable!()
294+
}
295+
};
296+
297+
// Next, if necessary, look for less obvious sources of equivalence.
298+
maybe_equiv = maybe_equiv
299+
|| match impl_ty.kind() {
300+
ty::Bool
301+
| ty::Char
302+
| ty::Int(_)
303+
| ty::Uint(_)
304+
| ty::Float(_)
305+
| ty::Adt(..)
306+
| ty::Str
307+
| ty::Array(..)
308+
| ty::Slice(..)
309+
| ty::RawPtr(..)
310+
| ty::Dynamic(..)
311+
| ty::Ref(..)
312+
| ty::Never
313+
| ty::Tuple(..)
314+
| ty::FnPtr(..)
315+
| ty::Foreign(..) => false,
316+
317+
ty::Param(_) | ty::Projection(_) | ty::Error(_) => true,
318+
319+
ty::FnDef(..)
320+
| ty::Closure(..)
321+
| ty::Generator(..)
322+
| ty::GeneratorWitness(..)
323+
| ty::Placeholder(..)
324+
| ty::Opaque(..)
325+
| ty::Bound(..)
326+
| ty::Infer(_) => unreachable!(),
327+
};
328+
329+
maybe_equiv
330+
}
331+
217332
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
218333
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
219334
SelectionContext {
@@ -2142,20 +2257,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21422257
|(obligation_arg, impl_arg)| {
21432258
match (obligation_arg.unpack(), impl_arg.unpack()) {
21442259
(GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => {
2145-
// Note, we simplify parameters for the obligation but not the
2146-
// impl so that we do not reject a blanket impl but do reject
2147-
// more concrete impls if we're searching for `T: Trait`.
2148-
let simplified_obligation_ty = fast_reject::simplify_type(
2149-
self.tcx(),
2150-
obligation_ty,
2151-
TreatParams::AsPlaceholder,
2152-
);
2153-
let simplified_impl_ty =
2154-
fast_reject::simplify_type(self.tcx(), impl_ty, TreatParams::AsInfer);
2155-
2156-
simplified_obligation_ty.is_some()
2157-
&& simplified_impl_ty.is_some()
2158-
&& simplified_obligation_ty != simplified_impl_ty
2260+
let tys_definitely_differ = !tys_may_be_equivalent(obligation_ty, impl_ty);
2261+
tys_definitely_differ
21592262
}
21602263
(GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => {
21612264
// Lifetimes can never cause a rejection.

0 commit comments

Comments
 (0)