mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +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
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool {
|
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool {
|
||||||
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify(t1, t2))
|
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 {
|
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
|
// try to resolve type vars first
|
||||||
let ty1 = self.resolve_ty_shallow(ty1);
|
let ty1 = self.resolve_ty_shallow(ty1);
|
||||||
let ty2 = self.resolve_ty_shallow(ty2);
|
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_id1, substs: substs1, .. },
|
||||||
Ty::Adt { def_id: def_id2, substs: substs2, .. },
|
Ty::Adt { def_id: def_id2, substs: substs2, .. },
|
||||||
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2),
|
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2, depth + 1),
|
||||||
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
|
(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(t1, t2),
|
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => {
|
||||||
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
|
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::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
|
||||||
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => {
|
(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::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
|
||||||
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(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 {
|
fn infer(content: &str) -> String {
|
||||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||||
let source_file = db.parse(file_id);
|
let source_file = db.parse(file_id);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue