mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 09:27:27 +00:00
Fix another crash, and try harder to prevent stack overflows
This commit is contained in:
parent
c0c3b37255
commit
a28d4befaf
3 changed files with 75 additions and 7 deletions
|
@ -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)))
|
||||
|
|
30
crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_5.snap
Normal file
30
crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_5.snap
Normal 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]
|
||||
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue