1923: Add SubstsBuilder r=flodiebold a=flodiebold

+ further refactoring.

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2019-09-26 21:04:20 +00:00 committed by GitHub
commit fc218ec0d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 212 additions and 126 deletions

View File

@ -339,10 +339,14 @@ pub struct Struct {
}
impl Struct {
pub fn module(self, db: &impl HirDatabase) -> Module {
pub fn module(self, db: &impl DefDatabase) -> Module {
self.id.module(db)
}
pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
self.module(db).krate(db)
}
pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.struct_data(self).name.clone()
}
@ -423,10 +427,14 @@ pub struct Enum {
}
impl Enum {
pub fn module(self, db: &impl HirDatabase) -> Module {
pub fn module(self, db: &impl DefDatabase) -> Module {
self.id.module(db)
}
pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
self.module(db).krate(db)
}
pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.enum_data(self).name.clone()
}
@ -514,7 +522,7 @@ impl Adt {
}
}
pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
match self {
Adt::Struct(s) => s.module(db),
Adt::Union(s) => s.module(db),

View File

@ -9,7 +9,6 @@ test_utils::marks!(
glob_across_crates
std_prelude
match_ergonomics_ref
trait_resolution_on_fn_type
infer_while_let
macro_rules_from_other_crates_are_visible_with_macro_use
prelude_is_macro_use

View File

@ -14,11 +14,11 @@ pub(crate) mod display;
use std::ops::Deref;
use std::sync::Arc;
use std::{fmt, mem};
use std::{fmt, iter, mem};
use crate::{
db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, DefWithBody, GenericParams, Name,
Trait, TypeAlias,
db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, Crate, DefWithBody, GenericParams,
HasGenericParams, Name, Trait, TypeAlias,
};
use display::{HirDisplay, HirFormatter};
@ -111,6 +111,81 @@ pub enum TypeCtor {
Closure { def: DefWithBody, expr: ExprId },
}
impl TypeCtor {
pub fn num_ty_params(self, db: &impl HirDatabase) -> usize {
match self {
TypeCtor::Bool
| TypeCtor::Char
| TypeCtor::Int(_)
| TypeCtor::Float(_)
| TypeCtor::Str
| TypeCtor::Never => 0,
TypeCtor::Slice
| TypeCtor::Array
| TypeCtor::RawPtr(_)
| TypeCtor::Ref(_)
| TypeCtor::Closure { .. } // 1 param representing the signature of the closure
=> 1,
TypeCtor::Adt(adt) => {
let generic_params = adt.generic_params(db);
generic_params.count_params_including_parent()
}
TypeCtor::FnDef(callable) => {
let generic_params = callable.generic_params(db);
generic_params.count_params_including_parent()
}
TypeCtor::AssociatedType(type_alias) => {
let generic_params = type_alias.generic_params(db);
generic_params.count_params_including_parent()
}
TypeCtor::FnPtr { num_args } => num_args as usize + 1,
TypeCtor::Tuple { cardinality } => cardinality as usize,
}
}
pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
match self {
TypeCtor::Bool
| TypeCtor::Char
| TypeCtor::Int(_)
| TypeCtor::Float(_)
| TypeCtor::Str
| TypeCtor::Never
| TypeCtor::Slice
| TypeCtor::Array
| TypeCtor::RawPtr(_)
| TypeCtor::Ref(_)
| TypeCtor::FnPtr { .. }
| TypeCtor::Tuple { .. } => None,
TypeCtor::Closure { def, .. } => def.krate(db),
TypeCtor::Adt(adt) => adt.krate(db),
TypeCtor::FnDef(callable) => callable.krate(db),
TypeCtor::AssociatedType(type_alias) => type_alias.krate(db),
}
}
pub fn as_generic_def(self) -> Option<crate::generics::GenericDef> {
match self {
TypeCtor::Bool
| TypeCtor::Char
| TypeCtor::Int(_)
| TypeCtor::Float(_)
| TypeCtor::Str
| TypeCtor::Never
| TypeCtor::Slice
| TypeCtor::Array
| TypeCtor::RawPtr(_)
| TypeCtor::Ref(_)
| TypeCtor::FnPtr { .. }
| TypeCtor::Tuple { .. }
| TypeCtor::Closure { .. } => None,
TypeCtor::Adt(adt) => Some(adt.into()),
TypeCtor::FnDef(callable) => Some(callable.into()),
TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()),
}
}
}
/// A nominal type with (maybe 0) type parameters. This might be a primitive
/// type like `bool`, a struct, tuple, function pointer, reference or
/// several other things.
@ -271,11 +346,65 @@ impl Substs {
.into(),
)
}
pub fn build_for_def(
db: &impl HirDatabase,
def: impl crate::HasGenericParams,
) -> SubstsBuilder {
let params = def.generic_params(db);
let param_count = params.count_params_including_parent();
Substs::builder(param_count)
}
pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder {
Substs::builder(generic_params.count_params_including_parent())
}
pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder {
Substs::builder(type_ctor.num_ty_params(db))
}
fn builder(param_count: usize) -> SubstsBuilder {
SubstsBuilder { vec: Vec::with_capacity(param_count), param_count }
}
}
impl From<Vec<Ty>> for Substs {
fn from(v: Vec<Ty>) -> Self {
Substs(v.into())
#[derive(Debug, Clone)]
pub struct SubstsBuilder {
vec: Vec<Ty>,
param_count: usize,
}
impl SubstsBuilder {
pub fn build(self) -> Substs {
assert_eq!(self.vec.len(), self.param_count);
Substs(self.vec.into())
}
pub fn push(mut self, ty: Ty) -> Self {
self.vec.push(ty);
self
}
fn remaining(&self) -> usize {
self.param_count - self.vec.len()
}
pub fn fill_with_bound_vars(mut self, starting_from: u32) -> Self {
self.vec.extend((starting_from..starting_from + self.remaining() as u32).map(Ty::Bound));
self
}
pub fn fill_with_unknown(mut self) -> Self {
self.vec.extend(iter::repeat(Ty::Unknown).take(self.remaining()));
self
}
pub fn use_parent_substs(mut self, parent_substs: &Substs) -> Self {
assert!(self.vec.is_empty());
assert!(parent_substs.len() <= self.param_count);
self.vec.extend(parent_substs.iter().cloned());
self
}
}

View File

@ -7,7 +7,7 @@ use std::iter::successors;
use log::{info, warn};
use super::{traits::Solution, Canonical, Ty, TypeWalk};
use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
use crate::{db::HirDatabase, name, HasGenericParams, Resolver};
const AUTODEREF_RECURSION_LIMIT: usize = 10;
@ -44,7 +44,8 @@ fn deref_by_trait(
};
let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
if target.generic_params(db).count_params_including_parent() != 1 {
let generic_params = target.generic_params(db);
if generic_params.count_params_including_parent() != 1 {
// the Target type + Deref trait should only have one generic parameter,
// namely Deref's Self type
return None;
@ -54,12 +55,13 @@ fn deref_by_trait(
let env = super::lower::trait_env(db, resolver);
let parameters = Substs::build_for_generics(&generic_params)
.push(ty.value.clone().shift_bound_vars(1))
.build();
let projection = super::traits::ProjectionPredicate {
ty: Ty::Bound(0),
projection_ty: super::ProjectionTy {
associated_ty: target,
parameters: vec![ty.value.clone().shift_bound_vars(1)].into(),
},
projection_ty: super::ProjectionTy { associated_ty: target, parameters },
};
let obligation = super::Obligation::Projection(projection);

View File

@ -688,14 +688,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
};
let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
let inner_tys: Substs = args
let inner_tys = args
.iter()
.zip(expectations_iter)
.map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
.collect::<Vec<_>>()
.into();
.collect();
Ty::apply(TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, inner_tys)
Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
}
Pat::Ref { pat, mutability } => {
let expectation = match expected.as_reference() {
@ -1229,7 +1228,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty: pat_ty.clone(),
projection_ty: ProjectionTy {
associated_ty: into_iter_item_alias,
parameters: vec![iterable_ty].into(),
parameters: Substs::single(iterable_ty),
},
};
self.obligations.push(Obligation::Projection(projection));
@ -1262,7 +1261,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
sig_tys.push(ret_ty.clone());
let sig_ty = Ty::apply(
TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
sig_tys.into(),
Substs(sig_tys.into()),
);
let closure_ty = Ty::apply_one(
TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
@ -1400,7 +1399,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty: ty.clone(),
projection_ty: ProjectionTy {
associated_ty: future_future_output_alias,
parameters: vec![inner_ty].into(),
parameters: Substs::single(inner_ty),
},
};
self.obligations.push(Obligation::Projection(projection));
@ -1419,7 +1418,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty: ty.clone(),
projection_ty: ProjectionTy {
associated_ty: ops_try_ok_alias,
parameters: vec![inner_ty].into(),
parameters: Substs::single(inner_ty),
},
};
self.obligations.push(Obligation::Projection(projection));

View File

@ -158,13 +158,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
AssocItem::Const(c) => ValueNs::Const(c),
AssocItem::TypeAlias(_) => unreachable!(),
};
let generics = item.generic_params(self.db);
let mut substs = Vec::with_capacity(generics.count_params_including_parent());
substs.extend(trait_ref.substs.iter().cloned());
substs.extend(std::iter::repeat(Ty::Unknown).take(generics.params.len()));
let substs = Substs::build_for_def(self.db, item)
.use_parent_substs(&trait_ref.substs)
.fill_with_unknown()
.build();
self.write_assoc_resolution(id, item);
Some((def, Some(substs.into())))
Some((def, Some(substs)))
}
fn resolve_ty_assoc_item(

View File

@ -3,7 +3,8 @@
use super::{InferenceContext, Obligation};
use crate::db::HirDatabase;
use crate::ty::{
Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk,
Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty,
TypeWalk,
};
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@ -74,12 +75,9 @@ where
}
fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef {
let substs = trait_ref
.substs
.iter()
.map(|ty| self.do_canonicalize_ty(ty.clone()))
.collect::<Vec<_>>();
TraitRef { trait_: trait_ref.trait_, substs: substs.into() }
let substs =
trait_ref.substs.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
TraitRef { trait_: trait_ref.trait_, substs: Substs(substs) }
}
fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@ -90,12 +88,9 @@ where
}
fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy {
let params = projection_ty
.parameters
.iter()
.map(|ty| self.do_canonicalize_ty(ty.clone()))
.collect::<Vec<_>>();
ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: params.into() }
let params =
projection_ty.parameters.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: Substs(params) }
}
fn do_canonicalize_projection_predicate(
@ -153,8 +148,7 @@ impl<T> Canonicalized<T> {
solution: Canonical<Vec<Ty>>,
) {
// the solution may contain new variables, which we need to convert to new inference vars
let new_vars =
(0..solution.num_vars).map(|_| ctx.new_type_var()).collect::<Vec<_>>().into();
let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect());
for (i, ty) in solution.value.into_iter().enumerate() {
let var = self.free_vars[i];
ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars));

View File

@ -239,14 +239,10 @@ impl Ty {
let traits = traits_from_env.flat_map(|t| t.all_super_traits(db));
for t in traits {
if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
let generics = t.generic_params(db);
let mut substs = Vec::new();
substs.push(self_ty.clone());
substs.extend(
iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1),
);
let substs =
Substs::build_for_def(db, t).push(self_ty.clone()).fill_with_unknown().build();
// FIXME handle type parameters on the segment
return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() });
return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
}
}
Ty::Unknown
@ -766,6 +762,16 @@ pub enum CallableDef {
}
impl_froms!(CallableDef: Function, Struct, EnumVariant);
impl CallableDef {
pub fn krate(self, db: &impl HirDatabase) -> Option<crate::Crate> {
match self {
CallableDef::Function(f) => f.krate(db),
CallableDef::Struct(s) => s.krate(db),
CallableDef::EnumVariant(e) => e.parent_enum(db).krate(db),
}
}
}
impl From<CallableDef> for GenericDef {
fn from(def: CallableDef) -> GenericDef {
match def {

View File

@ -10,7 +10,6 @@ use rustc_hash::FxHashMap;
use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
use crate::{
db::HirDatabase,
generics::HasGenericParams,
impl_block::{ImplBlock, ImplId},
nameres::CrateModuleId,
resolve::Resolver,
@ -331,20 +330,13 @@ fn generic_implements_goal(
trait_: Trait,
self_ty: Canonical<Ty>,
) -> Canonical<InEnvironment<super::Obligation>> {
let mut substs = Vec::new();
let generics = trait_.generic_params(db);
let num_vars = self_ty.num_vars;
substs.push(self_ty.value);
substs.extend(
generics
.params_including_parent()
.into_iter()
.skip(1)
.enumerate()
.map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
);
let substs = super::Substs::build_for_def(db, trait_)
.push(self_ty.value)
.fill_with_bound_vars(num_vars as u32)
.build();
let num_vars = substs.len() - 1 + self_ty.num_vars;
let trait_ref = TraitRef { trait_, substs: substs.into() };
let trait_ref = TraitRef { trait_, substs };
let obligation = super::Obligation::Trait(trait_ref);
Canonical { num_vars, value: InEnvironment::new(env, obligation) }
}

View File

@ -3321,7 +3321,6 @@ fn test() { S2.into()<|>; }
#[test]
fn method_resolution_encountering_fn_type() {
covers!(trait_resolution_on_fn_type);
type_at(
r#"
//- /main.rs

View File

@ -10,17 +10,13 @@ use chalk_ir::{
use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
use ra_db::salsa::{InternId, InternKey};
use test_utils::tested_by;
use super::{Canonical, ChalkContext, Impl, Obligation};
use crate::{
db::HirDatabase,
generics::GenericDef,
ty::display::HirDisplay,
ty::{
ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
TypeWalk,
},
ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk},
AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias,
};
@ -124,14 +120,15 @@ impl ToChalk for Substs {
}
fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
parameters
let tys = parameters
.into_iter()
.map(|p| match p {
chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
})
.collect::<Vec<_>>()
.into()
.into();
Substs(tys)
}
}
@ -539,60 +536,18 @@ pub(crate) fn struct_datum_query(
struct_id: chalk_ir::StructId,
) -> Arc<StructDatum> {
debug!("struct_datum {:?}", struct_id);
let type_ctor = from_chalk(db, struct_id);
let type_ctor: TypeCtor = from_chalk(db, struct_id);
debug!("struct {:?} = {:?}", struct_id, type_ctor);
// FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
// FIXME extract this to a method on Ty
let (num_params, where_clauses, upstream) = match type_ctor {
TypeCtor::Bool
| TypeCtor::Char
| TypeCtor::Int(_)
| TypeCtor::Float(_)
| TypeCtor::Never
| TypeCtor::Str => (0, vec![], true),
TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
(1, vec![], true)
}
TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
TypeCtor::FnDef(callable) => {
tested_by!(trait_resolution_on_fn_type);
let upstream = match callable {
CallableDef::Function(f) => f.module(db).krate(db),
CallableDef::Struct(s) => s.module(db).krate(db),
CallableDef::EnumVariant(v) => v.parent_enum(db).module(db).krate(db),
} != Some(krate);
let generic_def: GenericDef = callable.into();
let num_params = type_ctor.num_ty_params(db);
let upstream = type_ctor.krate(db) != Some(krate);
let where_clauses = type_ctor
.as_generic_def()
.map(|generic_def| {
let generic_params = generic_def.generic_params(db);
let bound_vars = Substs::bound_vars(&generic_params);
let where_clauses = convert_where_clauses(db, generic_def, &bound_vars);
(generic_params.count_params_including_parent(), where_clauses, upstream)
}
TypeCtor::Adt(adt) => {
let generic_params = adt.generic_params(db);
let bound_vars = Substs::bound_vars(&generic_params);
let where_clauses = convert_where_clauses(db, adt.into(), &bound_vars);
(
generic_params.count_params_including_parent(),
where_clauses,
adt.krate(db) != Some(krate),
)
}
TypeCtor::AssociatedType(type_alias) => {
let generic_params = type_alias.generic_params(db);
let bound_vars = Substs::bound_vars(&generic_params);
let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
(
generic_params.count_params_including_parent(),
where_clauses,
type_alias.krate(db) != Some(krate),
)
}
TypeCtor::Closure { def, .. } => {
let upstream = def.krate(db) != Some(krate);
(1, vec![], upstream)
}
};
convert_where_clauses(db, generic_def, &bound_vars)
})
.unwrap_or_else(Vec::new);
let flags = chalk_rust_ir::StructFlags {
upstream,
// FIXME set fundamental flag correctly
@ -729,17 +684,20 @@ fn closure_fn_trait_impl_datum(
let arg_ty = Ty::apply(
TypeCtor::Tuple { cardinality: num_args },
(0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
);
let output_ty = Ty::Bound(num_args.into());
let sig_ty = Ty::apply(
TypeCtor::FnPtr { num_args },
(0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
);
let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() };
let trait_ref = TraitRef {
trait_,
substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
};
let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?;