mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 15:14:32 +00:00
Adapt to the new generic parameter/argument order
This commit is contained in:
parent
4385d3dcd0
commit
78977cd86c
11 changed files with 259 additions and 161 deletions
|
@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
|
|||
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(db, target);
|
||||
let b = TyBuilder::subst_for_def(db, deref_trait, None);
|
||||
if b.remaining() != 1 {
|
||||
// the Target type + Deref trait should only have one generic parameter,
|
||||
// namely Deref's Self type
|
||||
return None;
|
||||
}
|
||||
b.push(ty).build()
|
||||
let deref_subst = b.push(ty).build();
|
||||
TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
|
||||
};
|
||||
|
||||
// Check that the type implements Deref at all
|
||||
|
|
|
@ -382,13 +382,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
// `resume_type`, `yield_type`, and `return_type` of the generator in question.
|
||||
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||
|
||||
let len = subst.len(Interner);
|
||||
let input_output = rust_ir::GeneratorInputOutputDatum {
|
||||
resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3))
|
||||
resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
|
||||
.intern(Interner),
|
||||
yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2))
|
||||
yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
|
||||
.intern(Interner),
|
||||
return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1))
|
||||
return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
|
||||
.intern(Interner),
|
||||
// FIXME: calculate upvars
|
||||
upvars: vec![],
|
||||
|
@ -476,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
|
|||
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
||||
let ctx = crate::TyLoweringContext::new(db, &resolver)
|
||||
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
|
||||
|
||||
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
|
||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
|
||||
.build();
|
||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
|
||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
|
||||
.build();
|
||||
let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
|
||||
|
||||
let mut bounds: Vec<_> = type_alias_data
|
||||
.bounds
|
||||
.iter()
|
||||
|
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
db::HirDatabase,
|
||||
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
|
||||
mapping::from_chalk,
|
||||
primitive, subst_prefix, to_assoc_type_id,
|
||||
primitive, to_assoc_type_id,
|
||||
utils::{self, generics},
|
||||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
|
||||
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
|
||||
|
@ -506,8 +506,15 @@ impl HirDisplay for Ty {
|
|||
let total_len = parent_params + self_param + type_params + const_params;
|
||||
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
|
||||
if total_len > 0 {
|
||||
// `parameters` are in the order of fn's params (including impl traits),
|
||||
// parent's params (those from enclosing impl or trait, if any).
|
||||
let parameters = parameters.as_slice(Interner);
|
||||
let fn_params_len = self_param + type_params + const_params;
|
||||
let fn_params = parameters.get(..fn_params_len);
|
||||
let parent_params = parameters.get(parameters.len() - parent_params..);
|
||||
let params = parent_params.into_iter().chain(fn_params).flatten();
|
||||
write!(f, "<")?;
|
||||
f.write_joined(¶meters.as_slice(Interner)[..total_len], ", ")?;
|
||||
f.write_joined(params, ", ")?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
}
|
||||
|
@ -579,9 +586,8 @@ impl HirDisplay for Ty {
|
|||
Some(x) => x,
|
||||
None => return true,
|
||||
};
|
||||
let actual_default = default_parameter
|
||||
.clone()
|
||||
.substitute(Interner, &subst_prefix(parameters, i));
|
||||
let actual_default =
|
||||
default_parameter.clone().substitute(Interner, ¶meters);
|
||||
parameter != &actual_default
|
||||
}
|
||||
let mut default_from = 0;
|
||||
|
|
|
@ -26,8 +26,8 @@ use hir_def::{
|
|||
path::{path, Path},
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
type_ref::TypeRef,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
|
||||
TraitId, TypeAliasId, VariantId,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
|
||||
ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use itertools::Either;
|
||||
|
@ -713,6 +713,8 @@ impl<'a> InferenceContext<'a> {
|
|||
&mut self,
|
||||
inner_ty: Ty,
|
||||
assoc_ty: Option<TypeAliasId>,
|
||||
// FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
|
||||
// handled when we support them.
|
||||
params: &[GenericArg],
|
||||
) -> Ty {
|
||||
match assoc_ty {
|
||||
|
@ -804,7 +806,18 @@ impl<'a> InferenceContext<'a> {
|
|||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
}
|
||||
TypeNs::TypeAliasId(it) => {
|
||||
let ty = TyBuilder::def_ty(self.db, it.into())
|
||||
let container = it.lookup(self.db.upcast()).container;
|
||||
let parent_subst = match container {
|
||||
ItemContainerId::TraitId(id) => {
|
||||
let subst = TyBuilder::subst_for_def(self.db, id, None)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
Some(subst)
|
||||
}
|
||||
// Type aliases do not exist in impls.
|
||||
_ => None,
|
||||
};
|
||||
let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
|
|
|
@ -987,11 +987,13 @@ impl<'a> InferenceContext<'a> {
|
|||
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
|
||||
let rhs_ty = self.table.new_type_var();
|
||||
|
||||
let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
|
||||
let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
|
||||
let func = self.db.trait_data(trait_id).method_by_name(&name)?;
|
||||
Some((trait_id, func))
|
||||
});
|
||||
let func = match func {
|
||||
Some(func) => func,
|
||||
let (trait_, func) = match trait_func {
|
||||
Some(it) => it,
|
||||
None => {
|
||||
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
|
||||
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
|
||||
|
@ -1001,7 +1003,9 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let subst = TyBuilder::subst_for_def(self.db, func)
|
||||
// HACK: We can use this substitution for the function because the function itself doesn't
|
||||
// have its own generic parameters.
|
||||
let subst = TyBuilder::subst_for_def(self.db, trait_, None)
|
||||
.push(lhs_ty.clone())
|
||||
.push(rhs_ty.clone())
|
||||
.build();
|
||||
|
@ -1280,19 +1284,7 @@ impl<'a> InferenceContext<'a> {
|
|||
assert_eq!(self_params, 0); // method shouldn't have another Self param
|
||||
let total_len = parent_params + type_params + const_params + impl_trait_params;
|
||||
let mut substs = Vec::with_capacity(total_len);
|
||||
// Parent arguments are unknown
|
||||
for (id, param) in def_generics.iter_parent() {
|
||||
match param {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
|
||||
substs
|
||||
.push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle provided arguments
|
||||
if let Some(generic_args) = generic_args {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
|
@ -1301,7 +1293,7 @@ impl<'a> InferenceContext<'a> {
|
|||
.iter()
|
||||
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
||||
.take(type_params + const_params)
|
||||
.zip(def_generics.iter_id().skip(parent_params))
|
||||
.zip(def_generics.iter_id())
|
||||
{
|
||||
if let Some(g) = generic_arg_to_chalk(
|
||||
self.db,
|
||||
|
@ -1325,6 +1317,9 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle everything else as unknown. This also handles generic arguments for the method's
|
||||
// parent (impl or trait), which should come after those for the method.
|
||||
for (id, data) in def_generics.iter().skip(substs.len()) {
|
||||
match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
|
@ -1362,9 +1357,13 @@ impl<'a> InferenceContext<'a> {
|
|||
CallableDefId::FunctionId(f) => {
|
||||
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
|
||||
// construct a TraitRef
|
||||
let substs = crate::subst_prefix(
|
||||
&*parameters,
|
||||
generics(self.db.upcast(), trait_.into()).len(),
|
||||
let params_len = parameters.len(Interner);
|
||||
let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
|
||||
let substs = Substitution::from_iter(
|
||||
Interner,
|
||||
// The generic parameters for the trait come after those for the
|
||||
// function.
|
||||
¶meters.as_slice(Interner)[params_len - trait_params_len..],
|
||||
);
|
||||
self.push_obligation(
|
||||
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
builder::ParamKind,
|
||||
consteval,
|
||||
method_resolution::{self, VisibleFromModule},
|
||||
utils::generics,
|
||||
Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
|
||||
};
|
||||
|
||||
|
@ -95,12 +96,18 @@ impl<'a> InferenceContext<'a> {
|
|||
ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
|
||||
};
|
||||
|
||||
let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
||||
let substs = ctx.substs_from_path(path, typable, true);
|
||||
let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable)
|
||||
.use_parent_substs(&parent_substs)
|
||||
let substs = substs.as_slice(Interner);
|
||||
let parent_substs = self_subst.or_else(|| {
|
||||
let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
|
||||
let parent_params_len = generics.parent_generics()?.len();
|
||||
let parent_args = &substs[substs.len() - parent_params_len..];
|
||||
Some(Substitution::from_iter(Interner, parent_args))
|
||||
});
|
||||
let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
|
||||
let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
|
||||
.fill(|x| {
|
||||
it.next().unwrap_or_else(|| match x {
|
||||
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||
|
@ -246,7 +253,7 @@ impl<'a> InferenceContext<'a> {
|
|||
};
|
||||
let substs = match container {
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
let impl_self_ty =
|
||||
|
|
|
@ -598,11 +598,14 @@ impl<'a> InferenceTable<'a> {
|
|||
.build();
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
|
||||
let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
|
||||
if b.remaining() != 2 {
|
||||
return None;
|
||||
}
|
||||
b.push(ty.clone()).push(arg_ty).build()
|
||||
let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
|
||||
|
||||
TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
|
||||
.build()
|
||||
};
|
||||
|
||||
let trait_env = self.trait_env.env.clone();
|
||||
|
|
|
@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// FIXME we're probably doing something wrong here
|
||||
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
|
||||
let (
|
||||
parent_params,
|
||||
_parent_params,
|
||||
self_params,
|
||||
list_params,
|
||||
const_params,
|
||||
|
@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
};
|
||||
TyKind::BoundVar(BoundVar::new(
|
||||
self.in_binders,
|
||||
idx as usize + parent_params + self_params + list_params + const_params,
|
||||
idx as usize + self_params + list_params + const_params,
|
||||
))
|
||||
.intern(Interner)
|
||||
}
|
||||
|
@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
|
|||
.intern(Interner)
|
||||
}
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
let generics = generics(self.db.upcast(), impl_id.into());
|
||||
let substs = match self.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
||||
ParamLoweringMode::Variable => {
|
||||
generics.bound_vars_subst(self.db, self.in_binders)
|
||||
let def =
|
||||
self.resolver.generic_def().expect("impl should have generic param scope");
|
||||
let generics = generics(self.db.upcast(), def);
|
||||
|
||||
match self.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
// `def` can be either impl itself or item within, and we need impl itself
|
||||
// now.
|
||||
let generics = generics.parent_generics().unwrap_or(&generics);
|
||||
let subst = generics.placeholder_subst(self.db);
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
|
||||
}
|
||||
};
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
|
||||
ParamLoweringMode::Variable => {
|
||||
let starting_from = match def {
|
||||
GenericDefId::ImplId(_) => 0,
|
||||
// `def` is an item within impl. We need to substitute `BoundVar`s but
|
||||
// remember that they are for parent (i.e. impl) generic params so they
|
||||
// come after our own params.
|
||||
_ => generics.len_self(),
|
||||
};
|
||||
TyBuilder::impl_self_ty(self.db, impl_id)
|
||||
.fill_with_bound_vars(self.in_binders, starting_from)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeNs::AdtSelfType(adt) => {
|
||||
let generics = generics(self.db.upcast(), adt.into());
|
||||
|
@ -636,13 +653,9 @@ impl<'a> TyLoweringContext<'a> {
|
|||
infer_args: bool,
|
||||
) -> Substitution {
|
||||
let last = path.segments().last().expect("path should have at least one segment");
|
||||
let (segment, generic_def) = match resolved {
|
||||
ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
|
||||
ValueTyDefId::StructId(it) => (last, Some(it.into())),
|
||||
ValueTyDefId::UnionId(it) => (last, Some(it.into())),
|
||||
ValueTyDefId::ConstId(it) => (last, Some(it.into())),
|
||||
ValueTyDefId::StaticId(_) => (last, None),
|
||||
ValueTyDefId::EnumVariantId(var) => {
|
||||
let generic_def = resolved.to_generic_def_id();
|
||||
let segment = match resolved {
|
||||
ValueTyDefId::EnumVariantId(_) => {
|
||||
// the generic args for an enum variant may be either specified
|
||||
// on the segment referring to the enum, or on the segment
|
||||
// referring to the variant. So `Option::<T>::None` and
|
||||
|
@ -650,12 +663,12 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// preferred). See also `def_ids_for_path_segments` in rustc.
|
||||
let len = path.segments().len();
|
||||
let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
|
||||
let segment = match penultimate {
|
||||
match penultimate {
|
||||
Some(segment) if segment.args_and_bindings.is_some() => segment,
|
||||
_ => last,
|
||||
};
|
||||
(segment, Some(var.parent.into()))
|
||||
}
|
||||
}
|
||||
_ => last,
|
||||
};
|
||||
self.substs_from_path_segment(segment, generic_def, infer_args, None)
|
||||
}
|
||||
|
@ -663,36 +676,27 @@ impl<'a> TyLoweringContext<'a> {
|
|||
fn substs_from_path_segment(
|
||||
&self,
|
||||
segment: PathSegment<'_>,
|
||||
def_generic: Option<GenericDefId>,
|
||||
def: Option<GenericDefId>,
|
||||
infer_args: bool,
|
||||
explicit_self_ty: Option<Ty>,
|
||||
) -> Substitution {
|
||||
// Remember that the item's own generic args come before its parent's.
|
||||
let mut substs = Vec::new();
|
||||
let def_generics = if let Some(def) = def_generic {
|
||||
generics(self.db.upcast(), def)
|
||||
let def = if let Some(d) = def {
|
||||
d
|
||||
} else {
|
||||
return Substitution::empty(Interner);
|
||||
};
|
||||
let def_generics = generics(self.db.upcast(), def);
|
||||
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
|
||||
def_generics.provenance_split();
|
||||
let total_len =
|
||||
parent_params + self_params + type_params + const_params + impl_trait_params;
|
||||
let item_len = self_params + type_params + const_params + impl_trait_params;
|
||||
let total_len = parent_params + item_len;
|
||||
|
||||
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
|
||||
|
||||
let mut def_generic_iter = def_generics.iter_id();
|
||||
|
||||
for _ in 0..parent_params {
|
||||
if let Some(eid) = def_generic_iter.next() {
|
||||
match eid {
|
||||
Either::Left(_) => substs.push(ty_error.clone()),
|
||||
Either::Right(x) => {
|
||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fill_self_params = || {
|
||||
for x in explicit_self_ty
|
||||
.into_iter()
|
||||
|
@ -757,37 +761,40 @@ impl<'a> TyLoweringContext<'a> {
|
|||
fill_self_params();
|
||||
}
|
||||
|
||||
// These params include those of parent.
|
||||
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
|
||||
.map(|eid| match eid {
|
||||
Either::Left(_) => ty_error.clone(),
|
||||
Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(remaining_params.len() + substs.len(), total_len);
|
||||
|
||||
// handle defaults. In expression or pattern path segments without
|
||||
// explicitly specified type arguments, missing type arguments are inferred
|
||||
// (i.e. defaults aren't used).
|
||||
if !infer_args || had_explicit_args {
|
||||
if let Some(def_generic) = def_generic {
|
||||
let defaults = self.db.generic_defaults(def_generic);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
let defaults = self.db.generic_defaults(def);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
let parent_from = item_len - substs.len();
|
||||
|
||||
for default_ty in defaults.iter().skip(substs.len()) {
|
||||
// each default can depend on the previous parameters
|
||||
let substs_so_far = Substitution::from_iter(Interner, substs.clone());
|
||||
if let Some(_id) = def_generic_iter.next() {
|
||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||
}
|
||||
}
|
||||
for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
|
||||
// each default can depend on the previous parameters
|
||||
let substs_so_far = Substitution::from_iter(
|
||||
Interner,
|
||||
substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
|
||||
);
|
||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||
}
|
||||
|
||||
// Keep parent's params as unknown.
|
||||
let mut remaining_params = remaining_params;
|
||||
substs.extend(remaining_params.drain(parent_from..));
|
||||
} else {
|
||||
substs.extend(remaining_params);
|
||||
}
|
||||
|
||||
// add placeholders for args that were not provided
|
||||
// FIXME: emit diagnostics in contexts where this is not allowed
|
||||
for eid in def_generic_iter {
|
||||
match eid {
|
||||
Either::Left(_) => substs.push(ty_error.clone()),
|
||||
Either::Right(x) => {
|
||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
|
||||
assert_eq!(substs.len(), total_len);
|
||||
|
||||
Substitution::from_iter(Interner, substs)
|
||||
}
|
||||
|
||||
|
@ -1168,10 +1175,18 @@ fn named_associated_type_shorthand_candidates<R>(
|
|||
}
|
||||
// Handle `Self::Type` referring to own associated type in trait definitions
|
||||
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
|
||||
let generics = generics(db.upcast(), trait_id.into());
|
||||
if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let trait_generics = generics(db.upcast(), trait_id.into());
|
||||
if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let def_generics = generics(db.upcast(), def);
|
||||
let starting_idx = match def {
|
||||
GenericDefId::TraitId(_) => 0,
|
||||
// `def` is an item within trait. We need to substitute `BoundVar`s but
|
||||
// remember that they are for parent (i.e. trait) generic params so they
|
||||
// come after our own params.
|
||||
_ => def_generics.len_self(),
|
||||
};
|
||||
let trait_ref = TyBuilder::trait_ref(db, trait_id)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||
.build();
|
||||
return search(trait_ref);
|
||||
}
|
||||
|
@ -1413,6 +1428,7 @@ pub(crate) fn generic_defaults_query(
|
|||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let generic_params = generics(db.upcast(), def);
|
||||
let parent_start_idx = generic_params.len_self();
|
||||
|
||||
let defaults = generic_params
|
||||
.iter()
|
||||
|
@ -1425,19 +1441,17 @@ pub(crate) fn generic_defaults_query(
|
|||
let val = unknown_const_as_generic(
|
||||
db.const_param_ty(ConstParamId::from_unchecked(id)),
|
||||
);
|
||||
return crate::make_binders_with_count(db, idx, &generic_params, val);
|
||||
return make_binders(db, &generic_params, val);
|
||||
}
|
||||
};
|
||||
let mut ty =
|
||||
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
|
||||
|
||||
// Each default can only refer to previous parameters.
|
||||
// type variable default referring to parameter coming
|
||||
// after it. This is forbidden (FIXME: report
|
||||
// diagnostic)
|
||||
ty = fallback_bound_vars(ty, idx);
|
||||
let val = GenericArgData::Ty(ty).intern(Interner);
|
||||
crate::make_binders_with_count(db, idx, &generic_params, val)
|
||||
// Type variable default referring to parameter coming
|
||||
// after it is forbidden (FIXME: report diagnostic)
|
||||
ty = fallback_bound_vars(ty, idx, parent_start_idx);
|
||||
crate::make_binders(db, &generic_params, ty.cast(Interner))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1454,15 +1468,14 @@ pub(crate) fn generic_defaults_recover(
|
|||
// we still need one default per parameter
|
||||
let defaults = generic_params
|
||||
.iter_id()
|
||||
.enumerate()
|
||||
.map(|(count, id)| {
|
||||
.map(|id| {
|
||||
let val = match id {
|
||||
itertools::Either::Left(_) => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
|
||||
};
|
||||
crate::make_binders_with_count(db, count, &generic_params, val)
|
||||
crate::make_binders(db, &generic_params, val)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1837,26 +1850,48 @@ pub(crate) fn const_or_path_to_chalk(
|
|||
}
|
||||
}
|
||||
|
||||
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
||||
/// num_vars_to_keep) by `TyKind::Unknown`.
|
||||
/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
|
||||
/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
|
||||
/// appears after the generic parameter of `param_index`.
|
||||
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
|
||||
s: T,
|
||||
num_vars_to_keep: usize,
|
||||
param_index: usize,
|
||||
parent_start: usize,
|
||||
) -> T {
|
||||
// Keep in mind that parent generic parameters, if any, come *after* those of the item in
|
||||
// question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
|
||||
// its parent respectively.
|
||||
let is_allowed = |index| {
|
||||
if param_index < parent_start {
|
||||
// The parameter of `param_index` is one from the item in question. Any parent generic
|
||||
// parameters or the item's generic parameters that come before `param_index` is
|
||||
// allowed.
|
||||
// [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
|
||||
// ^^^^^^ ^^^^^^^^^^ these are allowed
|
||||
!(param_index..parent_start).contains(&index)
|
||||
} else {
|
||||
// The parameter of `param_index` is one from the parent generics. Only parent generic
|
||||
// parameters that come before `param_index` are allowed.
|
||||
// [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
|
||||
// ^^^^^^ these are allowed
|
||||
(parent_start..param_index).contains(&index)
|
||||
}
|
||||
};
|
||||
|
||||
crate::fold_free_vars(
|
||||
s,
|
||||
|bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
TyKind::Error.intern(Interner)
|
||||
} else {
|
||||
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||
bound.shifted_in_from(binders).to_ty(Interner)
|
||||
} else {
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
},
|
||||
|ty, bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
unknown_const(ty.clone())
|
||||
} else {
|
||||
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||
bound.shifted_in_from(binders).to_const(Interner, ty)
|
||||
} else {
|
||||
unknown_const(ty.clone())
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -654,7 +654,7 @@ fn find_matching_impl(
|
|||
let r = table.run_in_snapshot(|table| {
|
||||
let impl_data = db.impl_data(impl_);
|
||||
let substs =
|
||||
TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
|
||||
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
|
||||
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
|
||||
|
||||
table
|
||||
|
@ -1147,10 +1147,9 @@ fn is_valid_candidate(
|
|||
}));
|
||||
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
|
||||
let self_ty_matches = table.run_in_snapshot(|table| {
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
|
||||
let expected_self_ty =
|
||||
subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
|
||||
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
table.unify(&expected_self_ty, &self_ty)
|
||||
});
|
||||
if !self_ty_matches {
|
||||
|
@ -1186,31 +1185,26 @@ fn is_valid_fn_candidate(
|
|||
|
||||
table.run_in_snapshot(|table| {
|
||||
let container = fn_id.lookup(db.upcast()).container;
|
||||
let impl_subst = match container {
|
||||
let (impl_subst, expect_self_ty) = match container {
|
||||
ItemContainerId::ImplId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||
let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
|
||||
(subst, self_ty)
|
||||
}
|
||||
ItemContainerId::TraitId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||
let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
|
||||
(subst, self_ty)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id)
|
||||
.use_parent_substs(&impl_subst)
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
|
||||
let expect_self_ty = match container {
|
||||
ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
|
||||
}
|
||||
// We should only get called for associated items (impl/trait)
|
||||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
check_that!(table.unify(&expect_self_ty, self_ty));
|
||||
|
||||
if let Some(receiver_ty) = receiver_ty {
|
||||
|
|
|
@ -61,7 +61,6 @@ use hir_ty::{
|
|||
diagnostics::BodyValidationDiagnostic,
|
||||
method_resolution::{self, TyFingerprint},
|
||||
primitive::UintTy,
|
||||
subst_prefix,
|
||||
traits::FnTrait,
|
||||
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
|
||||
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
||||
|
@ -1090,7 +1089,7 @@ impl Adt {
|
|||
pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
|
||||
let id = AdtId::from(self);
|
||||
let mut it = args.iter().map(|t| t.ty.clone());
|
||||
let ty = TyBuilder::def_ty(db, id.into())
|
||||
let ty = TyBuilder::def_ty(db, id.into(), None)
|
||||
.fill(|x| {
|
||||
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
|
||||
match x {
|
||||
|
@ -2547,7 +2546,7 @@ impl TypeParam {
|
|||
let resolver = self.id.parent().resolver(db.upcast());
|
||||
let ty = params.get(local_idx)?.clone();
|
||||
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
|
||||
let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
|
||||
let ty = ty.substitute(Interner, &subst);
|
||||
match ty.data(Interner) {
|
||||
GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
|
||||
_ => None,
|
||||
|
@ -2801,7 +2800,18 @@ impl Type {
|
|||
}
|
||||
|
||||
fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
|
||||
let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
|
||||
let ty_def = def.into();
|
||||
let parent_subst = match ty_def {
|
||||
TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(id) => {
|
||||
let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
|
||||
Some(subst)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
|
||||
Type::new(db, def, ty)
|
||||
}
|
||||
|
||||
|
@ -2941,7 +2951,11 @@ impl Type {
|
|||
alias: TypeAlias,
|
||||
) -> Option<Type> {
|
||||
let mut args = args.iter();
|
||||
let projection = TyBuilder::assoc_type_projection(db, alias.id)
|
||||
let trait_id = match alias.id.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(id) => id,
|
||||
_ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
|
||||
};
|
||||
let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
|
||||
.push(self.ty.clone())
|
||||
.fill(|x| {
|
||||
// FIXME: this code is not covered in tests.
|
||||
|
@ -2953,6 +2967,8 @@ impl Type {
|
|||
}
|
||||
})
|
||||
.build();
|
||||
// FIXME: We don't handle GATs yet.
|
||||
let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
|
||||
|
||||
let ty = db.normalize_projection(projection, self.env.clone());
|
||||
if ty.is_unknown() {
|
||||
|
|
|
@ -22,7 +22,7 @@ use hir_def::{
|
|||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||
type_ref::Mutability,
|
||||
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
|
||||
Lookup, ModuleDefId, VariantId,
|
||||
Lookup, ModuleDefId, TraitId, VariantId,
|
||||
};
|
||||
use hir_expand::{
|
||||
builtin_fn_macro::BuiltinFnLikeExpander,
|
||||
|
@ -302,10 +302,15 @@ impl SourceAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
let future_trait = db
|
||||
.lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
|
||||
.as_trait()?;
|
||||
let poll_fn = db
|
||||
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
|
||||
.as_function()?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
|
||||
// HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
|
||||
// doesn't have any generic parameters, so we skip building another subst for `poll()`.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
|
||||
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
|
||||
}
|
||||
|
||||
|
@ -321,8 +326,10 @@ impl SourceAnalyzer {
|
|||
};
|
||||
let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
|
||||
|
||||
let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
||||
let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||
}
|
||||
|
@ -337,8 +344,10 @@ impl SourceAnalyzer {
|
|||
|
||||
let lang_item_name = name![index];
|
||||
|
||||
let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
|
||||
let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
|
||||
.push(base_ty.clone())
|
||||
.push(index_ty.clone())
|
||||
.build();
|
||||
|
@ -354,10 +363,14 @@ impl SourceAnalyzer {
|
|||
let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
|
||||
let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
|
||||
|
||||
let op_fn = lang_names_for_bin_op(op)
|
||||
let (op_trait, op_fn) = lang_names_for_bin_op(op)
|
||||
.and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
|
||||
let substs =
|
||||
hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
|
||||
// HACK: subst for `index()` coincides with that for `Index` because `index()` itself
|
||||
// doesn't have any generic parameters, so we skip building another subst for `index()`.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
|
||||
.push(lhs.clone())
|
||||
.push(rhs.clone())
|
||||
.build();
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||
}
|
||||
|
@ -371,7 +384,13 @@ impl SourceAnalyzer {
|
|||
|
||||
let op_fn =
|
||||
db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
||||
let op_trait = match op_fn.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(id) => id,
|
||||
_ => return None,
|
||||
};
|
||||
// HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
|
||||
// doesn't have any generic parameters, so we skip building another subst for `branch()`.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||
}
|
||||
|
@ -799,9 +818,10 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
lang_trait: &Name,
|
||||
method_name: &Name,
|
||||
) -> Option<FunctionId> {
|
||||
db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
|
||||
.method_by_name(method_name)
|
||||
) -> Option<(TraitId, FunctionId)> {
|
||||
let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
|
||||
let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
|
||||
Some((trait_id, fn_id))
|
||||
}
|
||||
|
||||
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
|
||||
|
|
Loading…
Reference in a new issue