Skip to content

Commit 74afb04

Browse files
authored
Merge pull request #21497 from ileixe/issue-21315
feat(hir-ty): add method references_only_ty_error to detect type errors
2 parents b5eb57a + 71d114d commit 74afb04

3 files changed

Lines changed: 92 additions & 4 deletions

File tree

crates/hir-ty/src/method_resolution/probe.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,9 +1246,9 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
12461246
.filter(|step| step.reachable_via_deref)
12471247
.filter(|step| {
12481248
debug!("pick_all_method: step={:?}", step);
1249-
// skip types that are from a type error or that would require dereferencing
1250-
// a raw pointer
1251-
!step.self_ty.value.value.references_non_lt_error() && !step.from_unsafe_deref
1249+
// Skip types with type errors (but not const/lifetime errors, which are
1250+
// often spurious due to incomplete const evaluation) and raw pointer derefs.
1251+
!step.self_ty.value.value.references_only_ty_error() && !step.from_unsafe_deref
12521252
})
12531253
.try_for_each(|step| {
12541254
let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self

crates/hir-ty/src/next_solver/ty.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,11 @@ impl<'db> Ty<'db> {
508508
references_non_lt_error(&self)
509509
}
510510

511+
/// Whether the type contains a type error (ignoring const and lifetime errors).
512+
pub fn references_only_ty_error(self) -> bool {
513+
references_only_ty_error(&self)
514+
}
515+
511516
pub fn callable_sig(self, interner: DbInterner<'db>) -> Option<Binder<'db, FnSig<'db>>> {
512517
match self.kind() {
513518
TyKind::FnDef(callable, args) => {
@@ -777,6 +782,20 @@ impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesNonLifetimeError {
777782
}
778783
}
779784

785+
pub fn references_only_ty_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool {
786+
t.references_error() && t.visit_with(&mut ReferencesOnlyTyError).is_break()
787+
}
788+
789+
struct ReferencesOnlyTyError;
790+
791+
impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesOnlyTyError {
792+
type Result = ControlFlow<()>;
793+
794+
fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
795+
if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) }
796+
}
797+
}
798+
780799
impl<'db> std::fmt::Debug for Ty<'db> {
781800
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
782801
self.inner().internee.fmt(f)

crates/hir-ty/src/tests/regression/new_solver.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,76 @@ fn foo() {
471471
244..246 '_x': {unknown}
472472
249..257 'to_bytes': fn to_bytes() -> [u8; _]
473473
249..259 'to_bytes()': [u8; _]
474-
249..268 'to_byt..._vec()': {unknown}
474+
249..268 'to_byt..._vec()': Vec<<[u8; _] as Foo>::Item>
475+
"#]],
476+
);
477+
}
478+
479+
#[test]
480+
fn regression_21315() {
481+
check_infer(
482+
r#"
483+
struct Consts;
484+
impl Consts { const MAX: usize = 0; }
485+
486+
struct Between<const M: usize, const N: usize, T>(T);
487+
488+
impl<const M: usize, T> Between<M, { Consts::MAX }, T> {
489+
fn sep_once(self, _sep: &str, _other: Self) -> Self {
490+
self
491+
}
492+
}
493+
494+
trait Parser: Sized {
495+
fn at_least<const M: usize>(self) -> Between<M, { Consts::MAX }, Self> {
496+
Between(self)
497+
}
498+
fn at_most<const N: usize>(self) -> Between<0, N, Self> {
499+
Between(self)
500+
}
501+
}
502+
503+
impl Parser for char {}
504+
505+
fn test_at_least() {
506+
let num = '9'.at_least::<1>();
507+
let _ver = num.sep_once(".", num);
508+
}
509+
510+
fn test_at_most() {
511+
let num = '9'.at_most::<1>();
512+
}
513+
"#,
514+
expect![[r#"
515+
48..49 '0': usize
516+
182..186 'self': Between<M, _, T>
517+
188..192 '_sep': &'? str
518+
200..206 '_other': Between<M, _, T>
519+
222..242 '{ ... }': Between<M, _, T>
520+
232..236 'self': Between<M, _, T>
521+
300..304 'self': Self
522+
343..372 '{ ... }': Between<M, _, Self>
523+
353..360 'Between': fn Between<M, _, Self>(Self) -> Between<M, _, Self>
524+
353..366 'Between(self)': Between<M, _, Self>
525+
361..365 'self': Self
526+
404..408 'self': Self
527+
433..462 '{ ... }': Between<0, N, Self>
528+
443..450 'Between': fn Between<0, N, Self>(Self) -> Between<0, N, Self>
529+
443..456 'Between(self)': Between<0, N, Self>
530+
451..455 'self': Self
531+
510..587 '{ ...um); }': ()
532+
520..523 'num': Between<1, _, char>
533+
526..529 ''9'': char
534+
526..545 ''9'.at...:<1>()': Between<1, _, char>
535+
555..559 '_ver': Between<1, _, char>
536+
562..565 'num': Between<1, _, char>
537+
562..584 'num.se..., num)': Between<1, _, char>
538+
575..578 '"."': &'static str
539+
580..583 'num': Between<1, _, char>
540+
607..644 '{ ...>(); }': ()
541+
617..620 'num': Between<0, 1, char>
542+
623..626 ''9'': char
543+
623..641 ''9'.at...:<1>()': Between<0, 1, char>
475544
"#]],
476545
);
477546
}

0 commit comments

Comments
 (0)