Some cleanup
This commit is contained in:
parent
a1ed53a4f1
commit
9339241b78
3 changed files with 111 additions and 98 deletions
|
|
@ -461,6 +461,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
for segment in &path.segments[remaining_index..] {
|
||||
let ty = match resolved {
|
||||
Resolution::Def(def) => {
|
||||
// FIXME resolve associated items from traits as well
|
||||
let typable: Option<TypableDef> = def.into();
|
||||
let typable = typable?;
|
||||
|
||||
|
|
@ -750,12 +751,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
fn substs_for_method_call(
|
||||
&mut self,
|
||||
def_generics: Option<Arc<GenericParams>>,
|
||||
generic_args: &Option<GenericArgs>,
|
||||
generic_args: Option<&GenericArgs>,
|
||||
receiver_ty: &Ty,
|
||||
) -> Substs {
|
||||
let (parent_param_count, param_count) =
|
||||
def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len()));
|
||||
let mut substs = Vec::with_capacity(parent_param_count + param_count);
|
||||
// Parent arguments are unknown, except for the receiver type
|
||||
if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) {
|
||||
for param in &parent_generics.params {
|
||||
if param.name.as_known_name() == Some(crate::KnownName::SelfType) {
|
||||
|
|
@ -785,6 +787,100 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Substs(substs.into())
|
||||
}
|
||||
|
||||
fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
|
||||
match callable_ty {
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::FnDef(def) => {
|
||||
// add obligation for trait implementation, if this is a trait method
|
||||
// FIXME also register obligations from where clauses from the trait or impl and method
|
||||
match def {
|
||||
CallableDef::Function(f) => {
|
||||
if let Some(trait_) = f.parent_trait(self.db) {
|
||||
// construct a TraitDef
|
||||
let substs = a_ty.parameters.prefix(
|
||||
trait_.generic_params(self.db).count_params_including_parent(),
|
||||
);
|
||||
self.obligations
|
||||
.push(Obligation::Trait(TraitRef { trait_, substs }));
|
||||
}
|
||||
}
|
||||
CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_method_call(
|
||||
&mut self,
|
||||
tgt_expr: ExprId,
|
||||
receiver: ExprId,
|
||||
args: &[ExprId],
|
||||
method_name: &Name,
|
||||
generic_args: Option<&GenericArgs>,
|
||||
) -> Ty {
|
||||
let receiver_ty = self.infer_expr(receiver, &Expectation::none());
|
||||
let resolved = receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver);
|
||||
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
|
||||
Some((ty, func)) => {
|
||||
self.write_method_resolution(tgt_expr, func);
|
||||
(
|
||||
ty,
|
||||
self.db.type_for_def(func.into(), Namespace::Values),
|
||||
Some(func.generic_params(self.db)),
|
||||
)
|
||||
}
|
||||
None => (receiver_ty, Ty::Unknown, None),
|
||||
};
|
||||
let substs =
|
||||
self.substs_for_method_call(def_generics.clone(), generic_args, &derefed_receiver_ty);
|
||||
let method_ty = method_ty.apply_substs(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 {
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::FnPtr => {
|
||||
let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters);
|
||||
if !sig.params().is_empty() {
|
||||
(sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), sig.ret().clone())
|
||||
}
|
||||
}
|
||||
TypeCtor::FnDef(def) => {
|
||||
let sig = self.db.callable_item_signature(def);
|
||||
let ret_ty = sig.ret().clone().subst(&a_ty.parameters);
|
||||
|
||||
if !sig.params().is_empty() {
|
||||
let mut params_iter =
|
||||
sig.params().iter().map(|ty| ty.clone().subst(&a_ty.parameters));
|
||||
let receiver_ty = params_iter.next().unwrap();
|
||||
(receiver_ty, params_iter.collect(), ret_ty)
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), ret_ty)
|
||||
}
|
||||
}
|
||||
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
|
||||
},
|
||||
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
|
||||
};
|
||||
// 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() {
|
||||
Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty),
|
||||
_ => derefed_receiver_ty,
|
||||
};
|
||||
self.unify(&expected_receiver_ty, &actual_receiver_ty);
|
||||
|
||||
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
|
||||
for (arg, param) in args.iter().zip(param_iter) {
|
||||
self.infer_expr(*arg, &Expectation::has_type(param));
|
||||
}
|
||||
ret_ty
|
||||
}
|
||||
|
||||
fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
||||
let ty = match &body[tgt_expr] {
|
||||
|
|
@ -872,95 +968,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
ret_ty
|
||||
}
|
||||
Expr::MethodCall { receiver, args, method_name, generic_args } => {
|
||||
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
|
||||
let resolved =
|
||||
receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver);
|
||||
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
|
||||
Some((ty, func)) => {
|
||||
self.write_method_resolution(tgt_expr, func);
|
||||
(
|
||||
ty,
|
||||
self.db.type_for_def(func.into(), Namespace::Values),
|
||||
Some(func.generic_params(self.db)),
|
||||
)
|
||||
}
|
||||
None => (receiver_ty, Ty::Unknown, None),
|
||||
};
|
||||
let substs = self.substs_for_method_call(
|
||||
def_generics.clone(),
|
||||
generic_args,
|
||||
&derefed_receiver_ty,
|
||||
);
|
||||
let method_ty = method_ty.apply_substs(substs);
|
||||
let method_ty = self.insert_type_vars(method_ty);
|
||||
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::FnPtr => {
|
||||
let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters);
|
||||
if !sig.params().is_empty() {
|
||||
(
|
||||
sig.params()[0].clone(),
|
||||
sig.params()[1..].to_vec(),
|
||||
sig.ret().clone(),
|
||||
)
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), sig.ret().clone())
|
||||
}
|
||||
}
|
||||
TypeCtor::FnDef(def) => {
|
||||
let sig = self.db.callable_item_signature(def);
|
||||
let ret_ty = sig.ret().clone().subst(&a_ty.parameters);
|
||||
|
||||
// add obligation for trait implementation, if this is a trait method
|
||||
// FIXME also register obligations from where clauses from the trait or impl and method
|
||||
match def {
|
||||
CallableDef::Function(f) => {
|
||||
if let Some(trait_) = f.parent_trait(self.db) {
|
||||
// construct a TraitDef
|
||||
let substs = a_ty.parameters.prefix(
|
||||
def_generics
|
||||
.expect("trait parent should always have generics")
|
||||
.count_parent_params(),
|
||||
);
|
||||
self.obligations
|
||||
.push(Obligation::Trait(TraitRef { trait_, substs }));
|
||||
}
|
||||
}
|
||||
CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {}
|
||||
}
|
||||
|
||||
if !sig.params().is_empty() {
|
||||
let mut params_iter = sig
|
||||
.params()
|
||||
.iter()
|
||||
.map(|ty| ty.clone().subst(&a_ty.parameters));
|
||||
let receiver_ty = params_iter.next().unwrap();
|
||||
(receiver_ty, params_iter.collect(), ret_ty)
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), ret_ty)
|
||||
}
|
||||
}
|
||||
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
|
||||
},
|
||||
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
|
||||
};
|
||||
// Apply autoref so the below unification works correctly
|
||||
// FIXME: return correct autorefs/derefs from lookup_method
|
||||
let actual_receiver_ty = match expected_receiver_ty.as_reference() {
|
||||
Some((_, mutability)) => {
|
||||
Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty)
|
||||
}
|
||||
_ => derefed_receiver_ty,
|
||||
};
|
||||
self.unify(&expected_receiver_ty, &actual_receiver_ty);
|
||||
|
||||
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
|
||||
for (arg, param) in args.iter().zip(param_iter) {
|
||||
self.infer_expr(*arg, &Expectation::has_type(param));
|
||||
}
|
||||
ret_ty
|
||||
}
|
||||
Expr::MethodCall { receiver, args, method_name, generic_args } => self
|
||||
.infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()),
|
||||
Expr::Match { expr, arms } => {
|
||||
let expected = if expected.ty == Ty::Unknown {
|
||||
Expectation::has_type(self.new_type_var())
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
//! - Building the type for an item: This happens through the `type_for_def` query.
|
||||
//!
|
||||
//! This usually involves resolving names, collecting generic arguments etc.
|
||||
use std::iter;
|
||||
|
||||
use crate::{
|
||||
Function, Struct, StructField, Enum, EnumVariant, Path,
|
||||
|
|
@ -172,16 +173,18 @@ pub(super) fn substs_from_path_segment(
|
|||
) -> Substs {
|
||||
let mut substs = Vec::new();
|
||||
let parent_param_count = def_generics.count_parent_params();
|
||||
substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
|
||||
substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count));
|
||||
if add_self_param {
|
||||
// FIXME this add_self_param argument is kind of a hack: Traits have the
|
||||
// Self type as an implicit first type parameter, but it can't be
|
||||
// actually provided in the type arguments
|
||||
// (well, actually sometimes it can, in the form of type-relative paths: `<Foo as Default>::default()`)
|
||||
substs.push(Ty::Unknown);
|
||||
}
|
||||
if let Some(generic_args) = &segment.args_and_bindings {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
let param_count = def_generics.params.len();
|
||||
let self_param_correction = if add_self_param { 1 } else { 0 };
|
||||
let param_count = def_generics.params.len() - self_param_correction;
|
||||
for arg in generic_args.args.iter().take(param_count) {
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
|
|
|
|||
|
|
@ -233,15 +233,16 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
/// This creates Substs for a trait with the given Self type and type variables
|
||||
/// for all other parameters. This is kind of a hack since these aren't 'real'
|
||||
/// type variables; the resulting trait reference is just used for the
|
||||
/// preliminary method candidate check.
|
||||
fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs {
|
||||
let mut substs = Vec::new();
|
||||
let mut counter = 0;
|
||||
let generics = tr.generic_params(db);
|
||||
substs.push(self_ty);
|
||||
substs.extend(generics.params_including_parent().into_iter().skip(1).map(|_p| {
|
||||
let fresh_var = Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(counter)));
|
||||
counter += 1;
|
||||
fresh_var
|
||||
}));
|
||||
substs.extend(generics.params_including_parent().into_iter().skip(1).enumerate().map(
|
||||
|(i, _p)| Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(i as u32))),
|
||||
));
|
||||
substs.into()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue