AsMacroCall, FunctionId, TraitId, VariantId,
};
use hir_expand::{name::AsName, ExpansionInfo};
-use hir_ty::associated_type_shorthand_candidates;
+use hir_ty::{associated_type_shorthand_candidates, Interner};
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
}
fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
- self.analyze(call.syntax()).resolve_method_call(self.db, call)
+ self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id)
}
fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
- // FIXME: this erases Substs, we should instead record the correct
- // substitution during inference and use that
- let func = self.resolve_method_call(call)?;
- let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
+ let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
+ let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst);
let resolver = self.analyze(call.syntax()).resolver;
let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
let mut res = ty.as_callable(self.db)?;
&self,
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
- ) -> Option<FunctionId> {
+ ) -> Option<(FunctionId, Substitution)> {
let expr_id = self.expr_id(db, &call.clone().into())?;
self.infer.as_ref()?.method_resolution(expr_id)
}
for (id, expr) in body.exprs.iter() {
if let Expr::MethodCall { receiver, .. } = expr {
let function_id = match self.infer.method_resolution(id) {
- Some(id) => id,
+ Some((id, _)) => id,
None => continue,
};
return;
}
- // FIXME: note that we erase information about substs here. This
- // is not right, but, luckily, doesn't matter as we care only
- // about the number of params
- let callee = match self.infer.method_resolution(call_id) {
- Some(callee) => callee,
+ let (callee, subst) = match self.infer.method_resolution(call_id) {
+ Some(it) => it,
None => return,
};
- let sig =
- db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0;
+ let sig = db.callable_item_signature(callee.into()).substitute(&Interner, &subst);
(sig, args)
}
Expr::MethodCall { .. } => {
if infer
.method_resolution(current)
- .map(|func| db.function_data(func).is_unsafe())
+ .map(|(func, _)| db.function_data(func).is_unsafe())
.unwrap_or(false)
{
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
use crate::{
db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
- lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, TyBuilder,
- TyExt, TyKind,
+ lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution,
+ TyBuilder, TyExt, TyKind,
};
// This lint has a false positive here. See the link below for details.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct InferenceResult {
/// For each method call expr, records the function it resolves to.
- method_resolutions: FxHashMap<ExprId, FunctionId>,
+ method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
/// For each field access expr, records the field it resolves to.
field_resolutions: FxHashMap<ExprId, FieldId>,
/// For each struct literal or pattern, records the variant it resolves to.
}
impl InferenceResult {
- pub fn method_resolution(&self, expr: ExprId) -> Option<FunctionId> {
- self.method_resolutions.get(&expr).copied()
+ pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
+ self.method_resolutions.get(&expr).cloned()
}
pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
self.field_resolutions.get(&expr).copied()
self.table.propagate_diverging_flag();
let mut result = std::mem::take(&mut self.result);
for ty in result.type_of_expr.values_mut() {
- *ty = self.table.resolve_ty_completely(ty.clone());
+ *ty = self.table.resolve_completely(ty.clone());
}
for ty in result.type_of_pat.values_mut() {
- *ty = self.table.resolve_ty_completely(ty.clone());
+ *ty = self.table.resolve_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());
+ mismatch.expected = self.table.resolve_completely(mismatch.expected.clone());
+ mismatch.actual = self.table.resolve_completely(mismatch.actual.clone());
+ }
+ for (_, subst) in result.method_resolutions.values_mut() {
+ *subst = self.table.resolve_completely(subst.clone());
}
result
}
self.result.type_of_expr.insert(expr, ty);
}
- fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId) {
- self.result.method_resolutions.insert(expr, func);
+ fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
+ self.result.method_resolutions.insert(expr, (func, subst));
}
fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) {
method_name,
)
});
- let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
+ let (derefed_receiver_ty, method_ty, substs) = match resolved {
Some((ty, func)) => {
let ty = canonicalized_receiver.decanonicalize_ty(ty);
- self.write_method_resolution(tgt_expr, func);
- (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into())))
+ 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());
+ (ty, self.db.value_ty(func.into()), substs)
}
- None => (receiver_ty, Binders::empty(&Interner, self.err_ty()), None),
+ None => (
+ receiver_ty,
+ Binders::empty(&Interner, self.err_ty()),
+ Substitution::empty(&Interner),
+ ),
};
- let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
let method_ty = method_ty.substitute(&Interner, &substs);
- let method_ty = self.insert_type_vars(method_ty);
self.register_obligations_for_call(&method_ty);
let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
Some(sig) => {
fn substs_for_method_call(
&mut self,
- def_generics: Option<Generics>,
+ def_generics: Generics,
generic_args: Option<&GenericArgs>,
receiver_ty: &Ty,
) -> Substitution {
let (parent_params, self_params, type_params, impl_trait_params) =
- def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split());
+ def_generics.provenance_split();
assert_eq!(self_params, 0); // method shouldn't have another Self param
let total_len = parent_params + type_params + impl_trait_params;
let mut substs = Vec::with_capacity(total_len);
// Parent arguments are unknown, except for the receiver type
- if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
- for (_id, param) in parent_generics {
- if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
- substs.push(receiver_ty.clone());
- } else {
- substs.push(self.err_ty());
- }
+ for (_id, param) in def_generics.iter_parent() {
+ if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
+ substs.push(receiver_ty.clone());
+ } else {
+ substs.push(self.table.new_type_var());
}
}
// handle provided type arguments
};
let supplied_params = substs.len();
for _ in supplied_params..total_len {
- substs.push(self.err_ty());
+ substs.push(self.table.new_type_var());
}
assert_eq!(substs.len(), total_len);
Substitution::from_iter(&Interner, substs)
.expect("fold failed unexpectedly")
}
- pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
- self.resolve_with_fallback(ty, |_, _, d, _| d)
+ pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T::Result
+ where
+ T: HasInterner<Interner = Interner> + Fold<Interner>,
+ {
+ self.resolve_with_fallback(t, |_, _, d, _| d)
}
/// Unify two types and register new trait goals that arise from that.
)
}
+ #[test]
+ fn expected_type_generic_struct_field() {
+ check_expected_type_and_name(
+ r#"
+struct Foo<T> { a: T }
+fn foo() -> Foo<u32> {
+ Foo { a: $0 }
+}
+"#,
+ expect![[r#"ty: u32, name: a"#]],
+ )
+ }
+
#[test]
fn expected_type_struct_field_with_leading_char() {
cov_mark::check!(expected_type_struct_field_with_leading_char);
expect![[r#"ty: u32, name: ?"#]],
)
}
+
+ #[test]
+ fn expected_type_closure_param() {
+ check_expected_type_and_name(
+ r#"
+fn foo() {
+ bar(|| $0);
+}
+
+fn bar(f: impl FnOnce() -> u32) {}
+#[lang = "fn_once"]
+trait FnOnce { type Output; }
+"#,
+ expect![[r#"ty: u32, name: ?"#]],
+ );
+ }
+
+ #[test]
+ fn expected_type_generic_function() {
+ check_expected_type_and_name(
+ r#"
+fn foo() {
+ bar::<u32>($0);
+}
+
+fn bar<T>(t: T) {}
+"#,
+ expect![[r#"ty: u32, name: t"#]],
+ );
+ }
+
+ #[test]
+ fn expected_type_generic_method() {
+ check_expected_type_and_name(
+ r#"
+fn foo() {
+ S(1u32).bar($0);
+}
+
+struct S<T>(T);
+impl<T> S<T> {
+ fn bar(self, t: T) {}
+}
+"#,
+ expect![[r#"ty: u32, name: t"#]],
+ );
+ }
}
);
}
+#[test]
+fn test_fn_signature_for_generic_method() {
+ check(
+ r#"
+struct S<T>(T);
+impl<T> S<T> {
+ fn foo(&self, x: T) {}
+}
+
+fn main() { S(1u32).foo($0); }
+"#,
+ expect![[r#"
+ fn foo(&self, x: u32)
+ (<x: u32>)
+ "#]],
+ );
+}
+
#[test]
fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
check(