Fix another crash, and try harder to prevent stack overflows

This commit is contained in:
Florian Diebold 2019-02-09 21:31:31 +01:00
parent c0c3b37255
commit a28d4befaf
3 changed files with 75 additions and 7 deletions

View file

@ -879,11 +879,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty
}
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool {
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify(t1, t2))
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool {
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth))
}
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
self.unify_inner(ty1, ty2, 0)
}
fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
if depth > 1000 {
// prevent stackoverflows
panic!("infinite recursion in unification");
}
if ty1 == ty2 {
return true;
}
// try to resolve type vars first
let ty1 = self.resolve_ty_shallow(ty1);
let ty2 = self.resolve_ty_shallow(ty2);
@ -904,13 +915,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
(
Ty::Adt { def_id: def_id1, substs: substs1, .. },
Ty::Adt { def_id: def_id2, substs: substs2, .. },
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2),
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2),
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2, depth + 1),
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify_inner(t1, t2, depth + 1),
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => {
self.unify_inner(t1, t2, depth + 1)
}
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify_inner(t1, t2, depth + 1),
(Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => {
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify(t1, t2))
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth + 1))
}
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))

View file

@ -0,0 +1,30 @@
---
created: "2019-02-09T20:28:37.294693728Z"
creator: insta@0.6.1
source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
---
[27; 323) '{ ... } }': ()
[33; 321) 'for co... }': ()
[37; 44) 'content': &[unknown]
[48; 61) 'doesnt_matter': [unknown]
[62; 321) '{ ... }': ()
[76; 80) 'name': &&[unknown]
[83; 167) 'if doe... }': &&[unknown]
[86; 99) 'doesnt_matter': bool
[100; 129) '{ ... }': &&[unknown]
[114; 119) 'first': &&[unknown]
[135; 167) '{ ... }': &&[unknown]
[149; 157) '&content': &&[unknown]
[150; 157) 'content': &[unknown]
[182; 189) 'content': &&[unknown]
[192; 314) 'if ICE... }': &&[unknown]
[195; 232) 'ICE_RE..._VALUE': [unknown]
[195; 248) 'ICE_RE...&name)': bool
[242; 247) '&name': &&&[unknown]
[243; 247) 'name': &&[unknown]
[249; 277) '{ ... }': &&[unknown]
[263; 267) 'name': &&[unknown]
[283; 314) '{ ... }': &[unknown]
[297; 304) 'content': &[unknown]

View file

@ -693,6 +693,31 @@ pub fn primitive_type() {
);
}
#[test]
fn infer_std_crash_5() {
// taken from rustc
check_inference(
"infer_std_crash_5",
r#"
fn extra_compiler_flags() {
for content in doesnt_matter {
let name = if doesnt_matter {
first
} else {
&content
};
let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
name
} else {
content
};
}
}
"#,
);
}
fn infer(content: &str) -> String {
let (db, _, file_id) = MockDatabase::with_single_file(content);
let source_file = db.parse(file_id);