3050: Refactor type parameters, implement argument position impl trait r=matklad a=flodiebold

I wanted to implement APIT by lowering to type parameters because we need to do that anyway for correctness and don't need Chalk support for it; this grew into some more wide-ranging refactoring of how type parameters are handled 😅 

 - use Ty::Bound instead of Ty::Param to represent polymorphism, and explicitly
   count binders. This gets us closer to Chalk's way of doing things, and means
   that we now only use Param as a placeholder for an unknown type, e.g. within
   a generic function. I.e. we're never using Param in a situation where we want
   to substitute it, and the method to do that is gone; `subst` now always works
   on bound variables. (This changes how the types of generic functions print; 
   previously, you'd get something like `fn identity<i32>(T) -> T`, but now we
   display the substituted signature `fn identity<i32>(i32) -> i32`, which I think 
   makes more sense.)
 - once we do this, it's more natural to represent `Param` by a globally unique
   ID; the use of indices was mostly to make substituting easier. This also
   means we fix the bug where `Param` loses its name when going through Chalk.
 - I would actually like to rename `Param` to `Placeholder` to better reflect its use and
   get closer to Chalk, but I'll leave that to a follow-up.
 - introduce a context for type lowering, to allow lowering `impl Trait` to
   different things depending on where we are. And since we have that, we can
   also lower type parameters directly to variables instead of placeholders.
   Also, we'll be able to use this later to collect diagnostics.
 - implement argument position impl trait by lowering it to type parameters.
   I've realized that this is necessary to correctly implement it; e.g. consider
   `fn foo(impl Display) -> impl Something`. It's observable that the return
   type of e.g. `foo(1u32)` unifies with itself, but doesn't unify with e.g.
   `foo(1i32)`; so the return type needs to be parameterized by the argument
   type.

   
This fixes a few bugs as well:
 - type parameters 'losing' their name when they go through Chalk, as mentioned
   above (i.e. getting `[missing name]` somewhere)
 - impl trait not being considered as implementing the super traits (very
   noticeable for the `db` in RA)
 - the fact that argument impl trait was only turned into variables when the
   function got called caused type mismatches when the function was used as a
   value (fixes a few type mismatches in RA)

The one thing I'm not so happy with here is how we're lowering `impl Trait` types to variables; since `TypeRef`s don't have an identity currently, we just count how many of them we have seen while going through the function signature. That's quite fragile though, since we have to do it while desugaring generics and while lowering the type signature, and in the exact same order in both cases. We could consider either giving only `TypeRef::ImplTrait` a local id, or maybe just giving all `TypeRef`s an identity after all (we talked about this before)...

Follow-up tasks:
 - handle return position impl trait; we basically need to create a variable and some trait obligations for that variable
 - rename `Param` to `Placeholder`

Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2020-02-09 11:35:08 +00:00 committed by GitHub
commit 01836a0f35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1173 additions and 613 deletions

View file

@ -10,9 +10,9 @@ use hir_def::{
per_ns::PerNs,
resolver::HasResolver,
type_ref::{Mutability, TypeRef},
AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId,
LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
TypeParamId, UnionId,
AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId,
LocalEnumVariantId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId,
TraitId, TypeAliasId, TypeParamId, UnionId,
};
use hir_expand::{
diagnostics::DiagnosticSink,
@ -21,7 +21,7 @@ use hir_expand::{
};
use hir_ty::{
autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
};
use ra_db::{CrateId, Edition, FileId};
use ra_prof::profile;
@ -270,7 +270,13 @@ impl StructField {
pub fn ty(&self, db: &impl HirDatabase) -> Type {
let var_id = self.parent.into();
let ty = db.field_types(var_id)[self.id].clone();
let generic_def_id: GenericDefId = match self.parent {
VariantDef::Struct(it) => it.id.into(),
VariantDef::Union(it) => it.id.into(),
VariantDef::EnumVariant(it) => it.parent.id.into(),
};
let substs = Substs::type_params(db, generic_def_id);
let ty = db.field_types(var_id)[self.id].clone().subst(&substs);
Type::new(db, self.parent.module(db).id.krate.into(), var_id, ty)
}
@ -755,7 +761,7 @@ pub struct TypeParam {
impl TypeParam {
pub fn name(self, db: &impl HirDatabase) -> Name {
let params = db.generic_params(self.id.parent);
params.types[self.id.local_id].name.clone()
params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
}
pub fn module(self, db: &impl HirDatabase) -> Module {
@ -789,8 +795,9 @@ impl ImplBlock {
pub fn target_ty(&self, db: &impl HirDatabase) -> Type {
let impl_data = db.impl_data(self.id);
let resolver = self.id.resolver(db);
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let environment = TraitEnvironment::lower(db, &resolver);
let ty = Ty::from_hir(db, &resolver, &impl_data.target_type);
let ty = Ty::from_hir(&ctx, &impl_data.target_type);
Type {
krate: self.id.lookup(db).container.module(db).krate,
ty: InEnvironment { value: ty, environment },
@ -851,9 +858,10 @@ impl Type {
fn from_def(
db: &impl HirDatabase,
krate: CrateId,
def: impl HasResolver + Into<TyDefId>,
def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
) -> Type {
let ty = db.ty(def.into());
let substs = Substs::type_params(db, def);
let ty = db.ty(def.into()).subst(&substs);
Type::new(db, krate, def, ty)
}
@ -950,7 +958,7 @@ impl Type {
match a_ty.ctor {
TypeCtor::Tuple { .. } => {
for ty in a_ty.parameters.iter() {
let ty = ty.clone().subst(&a_ty.parameters);
let ty = ty.clone();
res.push(self.derived(ty));
}
}

View file

@ -178,6 +178,10 @@ impl SourceAnalyzer {
}
}
fn trait_env(&self, db: &impl HirDatabase) -> Arc<TraitEnvironment> {
TraitEnvironment::lower(db, &self.resolver)
}
pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) {
self.body_source_map.as_ref()?.node_expr(expr.as_ref())?
@ -186,14 +190,14 @@ impl SourceAnalyzer {
};
let ty = self.infer.as_ref()?[expr_id].clone();
let environment = TraitEnvironment::lower(db, &self.resolver);
let environment = self.trait_env(db);
Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
}
pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> {
let pat_id = self.pat_id(pat)?;
let ty = self.infer.as_ref()?[pat_id].clone();
let environment = TraitEnvironment::lower(db, &self.resolver);
let environment = self.trait_env(db);
Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
}