Unnamed repository; edit this file 'description' to name the repository.
Avoid type inference panic on bitslice methods
Should fix #10090, #10046, #10179. This is only a workaround, but the proper fix requires some bigger refactoring (also related to fixing #10058), and this at least prevents the crash.
Florian Diebold 2021-09-12
parent 3170599 · commit a2d9f7d
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/hir_ty/src/infer/coerce.rs2
-rw-r--r--crates/hir_ty/src/infer/expr.rs26
-rw-r--r--crates/hir_ty/src/infer/unify.rs9
-rw-r--r--crates/hir_ty/src/method_resolution.rs20
-rw-r--r--crates/hir_ty/src/tests/regression.rs32
6 files changed, 66 insertions, 27 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b028e76c17..3b0c29e87e 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2612,7 +2612,7 @@ impl Type {
None,
name,
method_resolution::LookupMode::MethodCall,
- callback,
+ &mut |ty, id| callback(&ty.value, id),
);
}
@@ -2664,7 +2664,7 @@ impl Type {
None,
name,
method_resolution::LookupMode::Path,
- callback,
+ &mut |ty, id| callback(&ty.value, id),
);
}
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 0f5859c433..4d7ac6fd85 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -277,7 +277,7 @@ impl<'a> InferenceContext<'a> {
continue;
}
- let referent_ty = canonicalized.decanonicalize_ty(referent_ty.value);
+ let referent_ty = canonicalized.decanonicalize_ty(&mut self.table, referent_ty);
// At this point, we have deref'd `a` to `referent_ty`. So
// imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index ea71cdd810..b0306d9148 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -328,10 +328,8 @@ impl<'a> InferenceContext<'a> {
},
);
let res = derefs.by_ref().find_map(|(callee_deref_ty, _)| {
- self.callable_sig(
- &canonicalized.decanonicalize_ty(callee_deref_ty.value),
- args.len(),
- )
+ let ty = &canonicalized.decanonicalize_ty(&mut self.table, callee_deref_ty);
+ self.callable_sig(ty, args.len())
});
let (param_tys, ret_ty): (Vec<Ty>, Ty) = match res {
Some(res) => {
@@ -510,17 +508,20 @@ impl<'a> InferenceContext<'a> {
},
);
let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| {
- let def_db = self.db.upcast();
let module = self.resolver.module();
+ let db = self.db;
let is_visible = |field_id: &FieldId| {
module
.map(|mod_id| {
- self.db.field_visibilities(field_id.parent)[field_id.local_id]
- .is_visible_from(def_db, mod_id)
+ db.field_visibilities(field_id.parent)[field_id.local_id]
+ .is_visible_from(db.upcast(), mod_id)
})
.unwrap_or(true)
};
- match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
+ match canonicalized
+ .decanonicalize_ty(&mut self.table, derefed_ty)
+ .kind(&Interner)
+ {
TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
substs
.as_slice(&Interner)
@@ -637,7 +638,7 @@ impl<'a> InferenceContext<'a> {
},
) {
Some(derefed_ty) => {
- canonicalized.decanonicalize_ty(derefed_ty.value)
+ canonicalized.decanonicalize_ty(&mut self.table, derefed_ty)
}
None => self.err_ty(),
}
@@ -740,8 +741,9 @@ impl<'a> InferenceContext<'a> {
krate,
index_trait,
);
- let self_ty =
- self_ty.map_or(self.err_ty(), |t| canonicalized.decanonicalize_ty(t.value));
+ let self_ty = self_ty.map_or(self.err_ty(), |t| {
+ canonicalized.decanonicalize_ty(&mut self.table, t)
+ });
self.resolve_associated_type_with_params(
self_ty,
self.resolve_ops_index_output(),
@@ -987,7 +989,7 @@ impl<'a> InferenceContext<'a> {
});
let (receiver_ty, method_ty, substs) = match resolved {
Some((ty, func)) => {
- let ty = canonicalized_receiver.decanonicalize_ty(ty);
+ let ty = canonicalized_receiver.decanonicalize_ty(&mut self.table, ty);
let generics = generics(self.db.upcast(), func.into());
let substs = self.substs_for_method_call(generics, generic_args, &ty);
self.write_method_resolution(tgt_expr, func, substs.clone());
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 9f1253825e..4c1e758904 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -41,8 +41,13 @@ where
}
impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
- pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty {
- chalk_ir::Substitute::apply(&self.free_vars, ty, &Interner)
+ /// this method is wrong and shouldn't exist
+ pub(super) fn decanonicalize_ty(&self, table: &mut InferenceTable, ty: Canonical<Ty>) -> Ty {
+ let mut vars = self.free_vars.clone();
+ while ty.binders.len(&Interner) > vars.len() {
+ vars.push(table.new_type_var().cast(&Interner));
+ }
+ chalk_ir::Substitute::apply(&vars, ty.value, &Interner)
}
pub(super) fn apply_solution(
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 3921c36551..3533d2010c 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -380,7 +380,7 @@ pub(crate) fn lookup_method(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: Option<ModuleId>,
name: &Name,
-) -> Option<(Ty, FunctionId)> {
+) -> Option<(Canonical<Ty>, FunctionId)> {
iterate_method_candidates(
ty,
db,
@@ -421,7 +421,7 @@ pub fn iterate_method_candidates<T>(
visible_from_module: Option<ModuleId>,
name: Option<&Name>,
mode: LookupMode,
- mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
+ mut callback: impl FnMut(&Canonical<Ty>, AssocItemId) -> Option<T>,
) -> Option<T> {
let mut slot = None;
iterate_method_candidates_dyn(
@@ -454,7 +454,7 @@ pub fn iterate_method_candidates_dyn(
visible_from_module: Option<ModuleId>,
name: Option<&Name>,
mode: LookupMode,
- callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
match mode {
LookupMode::MethodCall => {
@@ -520,7 +520,7 @@ fn iterate_method_candidates_with_autoref(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: Option<ModuleId>,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
iterate_method_candidates_by_receiver(
&deref_chain[0],
@@ -580,7 +580,7 @@ fn iterate_method_candidates_by_receiver(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: Option<ModuleId>,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
// We're looking for methods with *receiver* type receiver_ty. These could
// be found in any of the derefs of receiver_ty, so we have to go through
@@ -622,7 +622,7 @@ fn iterate_method_candidates_for_self_ty(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: Option<ModuleId>,
name: Option<&Name>,
- mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
+ mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
iterate_inherent_methods(
self_ty,
@@ -645,7 +645,7 @@ fn iterate_trait_method_candidates(
traits_in_scope: &FxHashSet<TraitId>,
name: Option<&Name>,
receiver_ty: Option<&Canonical<Ty>>,
- callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
let receiver_is_array = matches!(self_ty.value.kind(&Interner), chalk_ir::TyKind::Array(..));
// if ty is `dyn Trait`, the trait doesn't need to be in scope
@@ -697,7 +697,7 @@ fn iterate_trait_method_candidates(
}
known_implemented = true;
// FIXME: we shouldn't be ignoring the binders here
- callback(&self_ty.value, *item)?
+ callback(&self_ty, *item)?
}
}
ControlFlow::Continue(())
@@ -738,7 +738,7 @@ fn iterate_inherent_methods(
receiver_ty: Option<&Canonical<Ty>>,
krate: CrateId,
visible_from_module: Option<ModuleId>,
- callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
+ callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
let def_crates = match def_crates(db, &self_ty.value, krate) {
Some(k) => k,
@@ -773,7 +773,7 @@ fn iterate_inherent_methods(
cov_mark::hit!(impl_self_type_match_without_receiver);
continue;
}
- let receiver_ty = receiver_ty.map(|x| &x.value).unwrap_or(&self_ty.value);
+ let receiver_ty = receiver_ty.unwrap_or(&self_ty);
callback(receiver_ty, item)?;
}
}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 70a1c37dc0..618499fdc1 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1145,3 +1145,35 @@ impl<'a, T, DB: TypeMetadata> Output<'a, T, DB> {
"#,
);
}
+
+#[test]
+fn bitslice_panic() {
+ check_no_mismatches(
+ r#"
+//- minicore: option, deref
+
+pub trait BitView {
+ type Store;
+}
+
+pub struct Lsb0;
+
+pub struct BitArray<V: BitView> { }
+
+pub struct BitSlice<T> { }
+
+impl<V: BitView> core::ops::Deref for BitArray<V> {
+ type Target = BitSlice<V::Store>;
+}
+
+impl<T> BitSlice<T> {
+ pub fn split_first(&self) -> Option<(T, &Self)> { loop {} }
+}
+
+fn multiexp_inner() {
+ let exp: &BitArray<Foo>;
+ exp.split_first();
+}
+ "#,
+ );
+}