From 4bd446f5b3f8035d5db1fde1c6c50073e3f4fb2b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 16 May 2021 17:56:38 +0200 Subject: Get rid of resolve_ty_as_possible Instead use shallow resolving where necessary. --- crates/hir_ty/src/infer.rs | 34 +++++++++++++++--------------- crates/hir_ty/src/infer/coerce.rs | 4 ++-- crates/hir_ty/src/infer/expr.rs | 28 +++++++++++++------------ crates/hir_ty/src/infer/pat.rs | 19 ++++++++--------- crates/hir_ty/src/infer/path.rs | 2 +- crates/hir_ty/src/infer/unify.rs | 39 +++-------------------------------- crates/hir_ty/src/tests/regression.rs | 16 +++++++------- crates/hir_ty/src/tests/traits.rs | 2 +- 8 files changed, 56 insertions(+), 88 deletions(-) (limited to 'crates') diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 8cfc84b86..ab742e203 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs @@ -273,7 +273,7 @@ impl<'a> InferenceContext<'a> { } fn err_ty(&self) -> Ty { - TyKind::Error.intern(&Interner) + self.result.standard_types.unknown.clone() } fn resolve_all(mut self) -> InferenceResult { @@ -284,12 +284,14 @@ impl<'a> InferenceContext<'a> { self.table.propagate_diverging_flag(); let mut result = std::mem::take(&mut self.result); for ty in result.type_of_expr.values_mut() { - let resolved = self.table.resolve_ty_completely(ty.clone()); - *ty = resolved; + *ty = self.table.resolve_ty_completely(ty.clone()); } for ty in result.type_of_pat.values_mut() { - let resolved = self.table.resolve_ty_completely(ty.clone()); - *ty = resolved; + *ty = self.table.resolve_ty_completely(ty.clone()); + } + for mismatch in result.type_mismatches.values_mut() { + mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone()); + mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone()); } result } @@ -343,6 +345,14 @@ impl<'a> InferenceContext<'a> { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty.kind(&Interner) { TyKind::Error => self.table.new_type_var(), + TyKind::InferenceVar(..) => { + let ty_resolved = self.resolve_ty_shallow(&ty); + if ty_resolved.is_unknown() { + self.table.new_type_var() + } else { + ty + } + } _ => ty, } } @@ -371,18 +381,8 @@ impl<'a> InferenceContext<'a> { self.table.unify_inner(ty1, ty2) } - // FIXME get rid of this, instead resolve shallowly where necessary - /// Resolves the type as far as currently possible, replacing type variables - /// by their known types. All types returned by the infer_* functions should - /// be resolved as far as possible, i.e. contain no type variables with - /// known type. - fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { - self.resolve_obligations_as_possible(); - - self.table.resolve_ty_as_possible(ty) - } - fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { + self.resolve_obligations_as_possible(); self.table.resolve_ty_shallow(ty) } @@ -416,7 +416,7 @@ impl<'a> InferenceContext<'a> { }; self.push_obligation(trait_ref.cast(&Interner)); self.push_obligation(alias_eq.cast(&Interner)); - self.resolve_ty_as_possible(ty) + ty } None => self.err_ty(), } diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index c85c088f7..00b2b585f 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs @@ -19,12 +19,12 @@ impl<'a> InferenceContext<'a> { /// Unify two types, but may coerce the first one to the second one /// using "implicit coercion rules" if needed. pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { + let from_ty = self.resolve_ty_shallow(from_ty); + let to_ty = self.resolve_ty_shallow(to_ty); // TODO handle expectations properly if to_ty.is_unknown() { return true; } - let from_ty = self.resolve_ty_shallow(from_ty); - let to_ty = self.resolve_ty_shallow(to_ty); match self.coerce_inner(from_ty, &to_ty) { Ok(_result) => { // TODO deal with goals diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 6eaccd9b4..f5782ab24 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -35,7 +35,7 @@ use super::{ impl<'a> InferenceContext<'a> { pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { let ty = self.infer_expr_inner(tgt_expr, expected); - if ty.is_never() { + if self.resolve_ty_shallow(&ty).is_never() { // Any expression that produces a value of type `!` must have diverged self.diverges = Diverges::Always; } @@ -46,7 +46,7 @@ impl<'a> InferenceContext<'a> { TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, ); } - self.resolve_ty_as_possible(ty) + ty } /// Infer type of expression with possibly implicit coerce to the expected type. @@ -67,7 +67,7 @@ impl<'a> InferenceContext<'a> { expected.ty.clone() }; - self.resolve_ty_as_possible(ty) + ty } fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec, Ty)> { @@ -284,8 +284,7 @@ impl<'a> InferenceContext<'a> { // Now go through the argument patterns for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { - let resolved = self.resolve_ty_as_possible(arg_ty); - self.infer_pat(*arg_pat, &resolved, BindingMode::default()); + self.infer_pat(*arg_pat, &arg_ty, BindingMode::default()); } let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); @@ -525,14 +524,14 @@ impl<'a> InferenceContext<'a> { Expr::Ref { expr, rawness, mutability } => { let mutability = lower_to_chalk_mutability(*mutability); let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = - &expected.ty.as_reference_or_ptr() + &self.resolve_ty_shallow(&expected.ty).as_reference_or_ptr() { if *exp_mutability == Mutability::Mut && mutability == Mutability::Not { - // FIXME: throw type error - expected mut reference but found shared ref, + // FIXME: record type error - expected mut reference but found shared ref, // which cannot be coerced } if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { - // FIXME: throw type error - expected reference but found ptr, + // FIXME: record type error - expected reference but found ptr, // which cannot be coerced } Expectation::rvalue_hint(Ty::clone(exp_inner)) @@ -559,6 +558,7 @@ impl<'a> InferenceContext<'a> { } Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); + let inner_ty = self.resolve_ty_shallow(&inner_ty); match op { UnaryOp::Deref => match self.resolver.krate() { Some(krate) => { @@ -615,8 +615,10 @@ impl<'a> InferenceContext<'a> { _ => Expectation::none(), }; let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); + let lhs_ty = self.resolve_ty_shallow(&lhs_ty); let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone()); let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation)); + let rhs_ty = self.resolve_ty_shallow(&rhs_ty); let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone()); @@ -699,7 +701,7 @@ impl<'a> InferenceContext<'a> { } } Expr::Tuple { exprs } => { - let mut tys = match expected.ty.kind(&Interner) { + let mut tys = match self.resolve_ty_shallow(&expected.ty).kind(&Interner) { TyKind::Tuple(_, substs) => substs .iter(&Interner) .map(|a| a.assert_ty_ref(&Interner).clone()) @@ -716,7 +718,7 @@ impl<'a> InferenceContext<'a> { TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner) } Expr::Array(array) => { - let elem_ty = match expected.ty.kind(&Interner) { + let elem_ty = match self.resolve_ty_shallow(&expected.ty).kind(&Interner) { TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), _ => self.table.new_type_var(), }; @@ -788,7 +790,6 @@ impl<'a> InferenceContext<'a> { }; // use a new type variable if we got unknown here let ty = self.insert_type_vars_shallow(ty); - let ty = self.resolve_ty_as_possible(ty); self.write_expr_ty(tgt_expr, ty.clone()); ty } @@ -816,7 +817,6 @@ impl<'a> InferenceContext<'a> { } } - let ty = self.resolve_ty_as_possible(ty); self.infer_pat(*pat, &ty, BindingMode::default()); } Statement::Expr { expr, .. } => { @@ -894,7 +894,8 @@ impl<'a> InferenceContext<'a> { }; // Apply autoref so the below unification works correctly // FIXME: return correct autorefs from lookup_method - let actual_receiver_ty = match expected_receiver_ty.as_reference() { + let actual_receiver_ty = match self.resolve_ty_shallow(&expected_receiver_ty).as_reference() + { Some((_, lifetime, mutability)) => { TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner) } @@ -974,6 +975,7 @@ impl<'a> InferenceContext<'a> { } fn register_obligations_for_call(&mut self, callable_ty: &Ty) { + let callable_ty = self.resolve_ty_shallow(&callable_ty); if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) { let def: CallableDefId = from_chalk(self.db, *fn_def); let generic_predicates = self.db.generic_predicates(def.into()); diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index b15f4977d..9c8e3b6ae 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs @@ -94,14 +94,15 @@ impl<'a> InferenceContext<'a> { pub(super) fn infer_pat( &mut self, pat: PatId, - mut expected: &Ty, + expected: &Ty, mut default_bm: BindingMode, ) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem + let mut expected = self.resolve_ty_shallow(expected); if is_non_ref_pat(&body, pat) { while let Some((inner, _lifetime, mutability)) = expected.as_reference() { - expected = inner; + expected = self.resolve_ty_shallow(inner); default_bm = match default_bm { BindingMode::Move => BindingMode::Ref(mutability), BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), @@ -147,9 +148,9 @@ impl<'a> InferenceContext<'a> { } Pat::Or(ref pats) => { if let Some((first_pat, rest)) = pats.split_first() { - let ty = self.infer_pat(*first_pat, expected, default_bm); + let ty = self.infer_pat(*first_pat, &expected, default_bm); for pat in rest { - self.infer_pat(*pat, expected, default_bm); + self.infer_pat(*pat, &expected, default_bm); } ty } else { @@ -173,13 +174,13 @@ impl<'a> InferenceContext<'a> { Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( p.as_deref(), subpats, - expected, + &expected, default_bm, pat, *ellipsis, ), Pat::Record { path: p, args: fields, ellipsis: _ } => { - self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat) + self.infer_record_pat(p.as_deref(), fields, &expected, default_bm, pat) } Pat::Path(path) => { // FIXME use correct resolver for the surrounding expression @@ -193,7 +194,7 @@ impl<'a> InferenceContext<'a> { BindingMode::convert(*mode) }; let inner_ty = if let Some(subpat) = subpat { - self.infer_pat(*subpat, expected, default_bm) + self.infer_pat(*subpat, &expected, default_bm) } else { expected.clone() }; @@ -206,7 +207,6 @@ impl<'a> InferenceContext<'a> { } BindingMode::Move => inner_ty.clone(), }; - let bound_ty = self.resolve_ty_as_possible(bound_ty); self.write_pat_ty(pat, bound_ty); return inner_ty; } @@ -265,13 +265,12 @@ impl<'a> InferenceContext<'a> { }; // use a new type variable if we got error type here let ty = self.insert_type_vars_shallow(ty); - if !self.unify(&ty, expected) { + if !self.unify(&ty, &expected) { self.result.type_mismatches.insert( pat.into(), TypeMismatch { expected: expected.clone(), actual: ty.clone() }, ); } - let ty = self.resolve_ty_as_possible(ty); self.write_pat_ty(pat, ty.clone()); ty } diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index fd366e121..14c99eafd 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs @@ -65,7 +65,6 @@ impl<'a> InferenceContext<'a> { let typable: ValueTyDefId = match value { ValueNs::LocalBinding(pat) => { let ty = self.result.type_of_pat.get(pat)?.clone(); - let ty = self.resolve_ty_as_possible(ty); return Some(ty); } ValueNs::FunctionId(it) => it.into(), @@ -275,6 +274,7 @@ impl<'a> InferenceContext<'a> { name: &Name, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { + let ty = self.resolve_ty_shallow(ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index 278127c69..539e12420 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs @@ -24,6 +24,9 @@ impl<'a> InferenceContext<'a> { where T::Result: HasInterner, { + // try to resolve obligations before canonicalizing, since this might + // result in new knowledge about variables + self.resolve_obligations_as_possible(); self.table.canonicalize(t) } } @@ -216,7 +219,6 @@ impl<'a> InferenceTable<'a> { /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. pub(super) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { - let ty = self.resolve_ty_as_possible(ty); fold_tys( ty, |ty, _| match ty.kind(&Interner) { @@ -302,11 +304,6 @@ impl<'a> InferenceTable<'a> { self.resolve_with_fallback(ty, |_, _, d, _| d) } - // FIXME get rid of this, instead resolve shallowly where necessary - pub(crate) fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { - self.resolve_ty_as_possible_inner(&mut Vec::new(), ty) - } - /// Unify two types and register new trait goals that arise from that. // TODO give these two functions better names pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { @@ -344,36 +341,6 @@ impl<'a> InferenceTable<'a> { self.var_unification_table.normalize_ty_shallow(&Interner, ty).unwrap_or_else(|| ty.clone()) } - /// Resolves the type as far as currently possible, replacing type variables - /// by their known types. - fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { - fold_tys( - ty, - |ty, _| match ty.kind(&Interner) { - &TyKind::InferenceVar(tv, kind) => { - if tv_stack.contains(&tv) { - // recursive type - return self.type_variable_table.fallback_value(tv, kind); - } - if let Some(known_ty) = self.var_unification_table.probe_var(tv) { - // known_ty may contain other variables that are known by now - tv_stack.push(tv); - let result = self.resolve_ty_as_possible_inner( - tv_stack, - known_ty.assert_ty_ref(&Interner).clone(), - ); - tv_stack.pop(); - result - } else { - ty - } - } - _ => ty, - }, - DebruijnIndex::INNERMOST, - ) - } - pub fn register_obligation(&mut self, goal: Goal) { let in_env = InEnvironment::new(&self.trait_env.env, goal); self.register_obligation_in_env(in_env) diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 59a16f390..baef81590 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs @@ -117,19 +117,19 @@ fn recursive_vars_2() { "#, expect![[r#" 10..79 '{ ...x)]; }': () - 20..21 'x': {unknown} - 24..31 'unknown': {unknown} + 20..21 'x': &{unknown} + 24..31 'unknown': &{unknown} 41..42 'y': {unknown} 45..52 'unknown': {unknown} - 58..76 '[(x, y..., &x)]': [({unknown}, {unknown}); 2] - 59..65 '(x, y)': ({unknown}, {unknown}) - 60..61 'x': {unknown} + 58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2] + 59..65 '(x, y)': (&{unknown}, {unknown}) + 60..61 'x': &{unknown} 63..64 'y': {unknown} - 67..75 '(&y, &x)': (&{unknown}, &{unknown}) + 67..75 '(&y, &x)': (&{unknown}, {unknown}) 68..70 '&y': &{unknown} 69..70 'y': {unknown} - 72..74 '&x': &{unknown} - 73..74 'x': {unknown} + 72..74 '&x': &&{unknown} + 73..74 'x': &{unknown} "#]], ); } diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index f80cf9879..a5a2df54c 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -3104,7 +3104,7 @@ fn foo() { 568..573 'f(&s)': FnOnce::Output), (&Option,)> 570..572 '&s': &Option 571..572 's': Option - 549..562: expected Box)>, got Box<|_| -> ()> + 549..562: expected Box)>, got Box<|{unknown}| -> ()> "#]], ); } -- cgit v1.2.3