Skip to content

Commit a8a4f80

Browse files
bors[bot]flodiebold
andcommitted
Merge #773
773: Crash fixes r=matklad a=flodiebold This fixes a bunch of crashes found while running type inference on the whole rustc repo 😅 - avoid infinite recursion with ref bind patterns - avoid another infinite recursion - handle literal patterns, add a new LITERAL_PAT syntax node for this - fix an expect that's wrong on some invalid code Co-authored-by: Florian Diebold <[email protected]>
2 parents 8bcb84e + c098a3f commit a8a4f80

16 files changed

+338
-70
lines changed

crates/ra_hir/src/expr.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -831,25 +831,26 @@ impl ExprCollector {
831831
p.field_pat_list().expect("every struct should have a field list");
832832
let mut fields: Vec<_> = field_pat_list
833833
.bind_pats()
834-
.map(|bind_pat| {
834+
.filter_map(|bind_pat| {
835835
let ast_pat = ast::Pat::cast(bind_pat.syntax()).expect("bind pat is a pat");
836836
let pat = self.collect_pat(ast_pat);
837-
let name = bind_pat.name().expect("bind pat has a name").as_name();
838-
FieldPat { name, pat }
837+
let name = bind_pat.name()?.as_name();
838+
Some(FieldPat { name, pat })
839839
})
840840
.collect();
841-
let iter = field_pat_list.field_pats().map(|f| {
842-
let ast_pat = f.pat().expect("field pat always contains a pattern");
841+
let iter = field_pat_list.field_pats().filter_map(|f| {
842+
let ast_pat = f.pat()?;
843843
let pat = self.collect_pat(ast_pat);
844-
let name = f.name().expect("field pats always have a name").as_name();
845-
FieldPat { name, pat }
844+
let name = f.name()?.as_name();
845+
Some(FieldPat { name, pat })
846846
});
847847
fields.extend(iter);
848848

849849
Pat::Struct { path, args: fields }
850850
}
851851

852852
// TODO: implement
853+
ast::PatKind::LiteralPat(_) => Pat::Missing,
853854
ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing,
854855
};
855856
let syntax_ptr = SyntaxNodePtr::new(pat.syntax());

crates/ra_hir/src/marks.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ test_utils::marks!(
33
item_map_enum_importing
44
type_var_cycles_resolve_completely
55
type_var_cycles_resolve_as_possible
6+
type_var_resolves_to_int_var
67
);

crates/ra_hir/src/ty.rs

Lines changed: 50 additions & 22 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)))
@@ -989,19 +1002,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
9891002
/// If `ty` is a type variable with known type, returns that type;
9901003
/// otherwise, return ty.
9911004
fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
992-
match ty {
993-
Ty::Infer(tv) => {
994-
let inner = tv.to_inner();
995-
match self.var_unification_table.probe_value(inner).known() {
996-
Some(known_ty) => {
997-
// The known_ty can't be a type var itself
998-
Cow::Owned(known_ty.clone())
1005+
let mut ty = Cow::Borrowed(ty);
1006+
// The type variable could resolve to a int/float variable. Hence try
1007+
// resolving up to three times; each type of variable shouldn't occur
1008+
// more than once
1009+
for i in 0..3 {
1010+
if i > 0 {
1011+
tested_by!(type_var_resolves_to_int_var);
1012+
}
1013+
match &*ty {
1014+
Ty::Infer(tv) => {
1015+
let inner = tv.to_inner();
1016+
match self.var_unification_table.probe_value(inner).known() {
1017+
Some(known_ty) => {
1018+
// The known_ty can't be a type var itself
1019+
ty = Cow::Owned(known_ty.clone());
1020+
}
1021+
_ => return ty,
9991022
}
1000-
_ => Cow::Borrowed(ty),
10011023
}
1024+
_ => return ty,
10021025
}
1003-
_ => Cow::Borrowed(ty),
10041026
}
1027+
log::error!("Inference variable still not resolved: {:?}", ty);
1028+
ty
10051029
}
10061030

10071031
/// Resolves the type completely; type variables without known type are
@@ -1185,17 +1209,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
11851209
self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown)
11861210
}
11871211
Pat::Bind { mode, name: _name, subpat } => {
1188-
let subty = if let Some(subpat) = subpat {
1212+
let inner_ty = if let Some(subpat) = subpat {
11891213
self.infer_pat(*subpat, expected)
11901214
} else {
11911215
expected.clone()
11921216
};
1217+
let inner_ty = self.insert_type_vars_shallow(inner_ty);
11931218

1194-
match mode {
1195-
BindingAnnotation::Ref => Ty::Ref(subty.into(), Mutability::Shared),
1196-
BindingAnnotation::RefMut => Ty::Ref(subty.into(), Mutability::Mut),
1197-
BindingAnnotation::Mutable | BindingAnnotation::Unannotated => subty,
1198-
}
1219+
let bound_ty = match mode {
1220+
BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared),
1221+
BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut),
1222+
BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(),
1223+
};
1224+
let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
1225+
self.write_pat_ty(pat, bound_ty);
1226+
return inner_ty;
11991227
}
12001228
_ => Ty::Unknown,
12011229
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
created: "2019-02-09T16:56:24.803326529Z"
3+
creator: insta@0.6.1
4+
source: crates/ra_hir/src/ty/tests.rs
5+
expression: "&result"
6+
---
7+
[54; 139) '{ ... } }': ()
8+
[60; 137) 'match ... }': ()
9+
[66; 83) 'someth...nknown': Maybe<[unknown]>
10+
[94; 124) 'Maybe:...thing)': Maybe<[unknown]>
11+
[106; 123) 'ref mu...ething': &mut [unknown]
12+
[128; 130) '()': ()
13+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
created: "2019-02-09T17:03:11.974225590Z"
3+
creator: insta@0.6.1
4+
source: crates/ra_hir/src/ty/tests.rs
5+
expression: "&result"
6+
---
7+
[23; 53) '{ ...n']; }': ()
8+
[29; 50) '&[0, b...b'\n']': &[u8]
9+
[30; 50) '[0, b'...b'\n']': [u8]
10+
[31; 32) '0': u8
11+
[34; 39) 'b'\n'': u8
12+
[41; 42) '1': u8
13+
[44; 49) 'b'\n'': u8
14+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
created: "2019-02-09T18:02:37.377591660Z"
3+
creator: insta@0.6.1
4+
source: crates/ra_hir/src/ty/tests.rs
5+
expression: "&result"
6+
---
7+
[18; 102) '{ ... } }': ()
8+
[24; 100) 'match ... }': ()
9+
[42; 88) 'SizeSk...tail }': [unknown]
10+
[76; 80) 'true': [unknown]
11+
[82; 86) 'tail': [unknown]
12+
[92; 94) '{}': ()
13+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
created: "2019-02-09T19:55:39.712470520Z"
3+
creator: insta@0.6.1
4+
source: crates/ra_hir/src/ty/tests.rs
5+
expression: "&result"
6+
---
7+
[25; 110) '{ ... } }': ()
8+
[31; 108) 'match ... }': ()
9+
[37; 42) '*self': [unknown]
10+
[38; 42) 'self': [unknown]
11+
[53; 95) 'Borrow...), ..}': [unknown]
12+
[74; 77) 'box': [unknown]
13+
[78; 87) 'Primitive': [unknown]
14+
[88; 89) 'p': [unknown]
15+
[99; 101) '{}': ()
16+
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: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,95 @@ fn test() {
630630
);
631631
}
632632

633+
#[test]
634+
fn infer_std_crash_1() {
635+
// caused stack overflow, taken from std
636+
check_inference(
637+
"infer_std_crash_1",
638+
r#"
639+
enum Maybe<T> {
640+
Real(T),
641+
Fake,
642+
}
643+
644+
fn write() {
645+
match something_unknown {
646+
Maybe::Real(ref mut something) => (),
647+
}
648+
}
649+
"#,
650+
);
651+
}
652+
653+
#[test]
654+
fn infer_std_crash_2() {
655+
covers!(type_var_resolves_to_int_var);
656+
// caused "equating two type variables, ...", taken from std
657+
check_inference(
658+
"infer_std_crash_2",
659+
r#"
660+
fn test_line_buffer() {
661+
&[0, b'\n', 1, b'\n'];
662+
}
663+
"#,
664+
);
665+
}
666+
667+
#[test]
668+
fn infer_std_crash_3() {
669+
// taken from rustc
670+
check_inference(
671+
"infer_std_crash_3",
672+
r#"
673+
pub fn compute() {
674+
match _ {
675+
SizeSkeleton::Pointer { non_zero: true, tail } => {}
676+
}
677+
}
678+
"#,
679+
);
680+
}
681+
682+
#[test]
683+
fn infer_std_crash_4() {
684+
// taken from rustc
685+
check_inference(
686+
"infer_std_crash_4",
687+
r#"
688+
pub fn primitive_type() {
689+
match *self {
690+
BorrowedRef { type_: box Primitive(p), ..} => {},
691+
}
692+
}
693+
"#,
694+
);
695+
}
696+
697+
#[test]
698+
fn infer_std_crash_5() {
699+
// taken from rustc
700+
check_inference(
701+
"infer_std_crash_5",
702+
r#"
703+
fn extra_compiler_flags() {
704+
for content in doesnt_matter {
705+
let name = if doesnt_matter {
706+
first
707+
} else {
708+
&content
709+
};
710+
711+
let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
712+
name
713+
} else {
714+
content
715+
};
716+
}
717+
}
718+
"#,
719+
);
720+
}
721+
633722
fn infer(content: &str) -> String {
634723
let (db, _, file_id) = MockDatabase::with_single_file(content);
635724
let source_file = db.parse(file_id);

0 commit comments

Comments
 (0)