Skip to content

Commit a28d4be

Browse files
committed
Fix another crash, and try harder to prevent stack overflows
1 parent c0c3b37 commit a28d4be

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

crates/ra_hir/src/ty.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -879,11 +879,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
879879
ty
880880
}
881881

882-
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool {
883-
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify(t1, t2))
882+
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool {
883+
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth))
884884
}
885885

886886
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
887+
self.unify_inner(ty1, ty2, 0)
888+
}
889+
890+
fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
891+
if depth > 1000 {
892+
// prevent stackoverflows
893+
panic!("infinite recursion in unification");
894+
}
895+
if ty1 == ty2 {
896+
return true;
897+
}
887898
// try to resolve type vars first
888899
let ty1 = self.resolve_ty_shallow(ty1);
889900
let ty2 = self.resolve_ty_shallow(ty2);
@@ -904,13 +915,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
904915
(
905916
Ty::Adt { def_id: def_id1, substs: substs1, .. },
906917
Ty::Adt { def_id: def_id2, substs: substs2, .. },
907-
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2),
908-
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
909-
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2),
910-
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
918+
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2, depth + 1),
919+
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify_inner(t1, t2, depth + 1),
920+
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => {
921+
self.unify_inner(t1, t2, depth + 1)
922+
}
923+
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify_inner(t1, t2, depth + 1),
911924
(Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
912925
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => {
913-
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify(t1, t2))
926+
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth + 1))
914927
}
915928
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
916929
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
created: "2019-02-09T20:28:37.294693728Z"
3+
creator: insta@0.6.1
4+
source: crates/ra_hir/src/ty/tests.rs
5+
expression: "&result"
6+
---
7+
[27; 323) '{ ... } }': ()
8+
[33; 321) 'for co... }': ()
9+
[37; 44) 'content': &[unknown]
10+
[48; 61) 'doesnt_matter': [unknown]
11+
[62; 321) '{ ... }': ()
12+
[76; 80) 'name': &&[unknown]
13+
[83; 167) 'if doe... }': &&[unknown]
14+
[86; 99) 'doesnt_matter': bool
15+
[100; 129) '{ ... }': &&[unknown]
16+
[114; 119) 'first': &&[unknown]
17+
[135; 167) '{ ... }': &&[unknown]
18+
[149; 157) '&content': &&[unknown]
19+
[150; 157) 'content': &[unknown]
20+
[182; 189) 'content': &&[unknown]
21+
[192; 314) 'if ICE... }': &&[unknown]
22+
[195; 232) 'ICE_RE..._VALUE': [unknown]
23+
[195; 248) 'ICE_RE...&name)': bool
24+
[242; 247) '&name': &&&[unknown]
25+
[243; 247) 'name': &&[unknown]
26+
[249; 277) '{ ... }': &&[unknown]
27+
[263; 267) 'name': &&[unknown]
28+
[283; 314) '{ ... }': &[unknown]
29+
[297; 304) 'content': &[unknown]
30+

crates/ra_hir/src/ty/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,31 @@ pub fn primitive_type() {
693693
);
694694
}
695695

696+
#[test]
697+
fn infer_std_crash_5() {
698+
// taken from rustc
699+
check_inference(
700+
"infer_std_crash_5",
701+
r#"
702+
fn extra_compiler_flags() {
703+
for content in doesnt_matter {
704+
let name = if doesnt_matter {
705+
first
706+
} else {
707+
&content
708+
};
709+
710+
let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
711+
name
712+
} else {
713+
content
714+
};
715+
}
716+
}
717+
"#,
718+
);
719+
}
720+
696721
fn infer(content: &str) -> String {
697722
let (db, _, file_id) = MockDatabase::with_single_file(content);
698723
let source_file = db.parse(file_id);

0 commit comments

Comments
 (0)