Skip to content

Commit 2a3ab7f

Browse files
Merge #4689
4689: Implement return position impl trait / opaque type support r=matklad a=flodiebold This is working, but I'm not that happy with how the lowering works. We might need an additional representation between `TypeRef` and `Ty` where names are resolved and `impl Trait` bounds are separated out, but things like inference variables don't exist and `impl Trait` is always represented the same way. Also note that this doesn't implement correct handling of RPIT *inside* the function (which involves turning the `impl Trait`s into variables and creating obligations for them). That intermediate representation might help there as well. Co-authored-by: Florian Diebold <flodiebold@gmail.com> Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
2 parents f133159 + 0d2328f commit 2a3ab7f

File tree

12 files changed

+442
-81
lines changed

12 files changed

+442
-81
lines changed

crates/ra_hir/src/db.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub use hir_ty::db::{
1818
GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
1919
HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery,
2020
ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
21-
InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery,
22-
TraitSolveQuery, TyQuery, ValueTyQuery,
21+
InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
22+
TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
2323
};
2424

2525
#[test]

crates/ra_hir_ty/src/db.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use std::sync::Arc;
44

55
use hir_def::{
6-
db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalFieldId, TraitId, TypeParamId,
7-
VariantId,
6+
db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId,
7+
TypeParamId, VariantId,
88
};
99
use ra_arena::map::ArenaMap;
1010
use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
@@ -13,8 +13,8 @@ use ra_prof::profile;
1313
use crate::{
1414
method_resolution::{CrateImplDefs, TyFingerprint},
1515
traits::{chalk, AssocTyValue, Impl},
16-
Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
17-
TyDefId, TypeCtor, ValueTyDefId,
16+
Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17+
ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
1818
};
1919
use hir_expand::name::Name;
2020

@@ -48,6 +48,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
4848
#[salsa::invoke(crate::callable_item_sig)]
4949
fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig;
5050

51+
#[salsa::invoke(crate::lower::return_type_impl_traits)]
52+
fn return_type_impl_traits(
53+
&self,
54+
def: FunctionId,
55+
) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;
56+
5157
#[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
5258
#[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
5359
fn generic_predicates_for_param(
@@ -80,6 +86,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
8086
#[salsa::interned]
8187
fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
8288
#[salsa::interned]
89+
fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId;
90+
#[salsa::interned]
8391
fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
8492
#[salsa::interned]
8593
fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
@@ -142,3 +150,7 @@ fn hir_database_is_object_safe() {
142150
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
143151
pub struct GlobalTypeParamId(salsa::InternId);
144152
impl_intern_key!(GlobalTypeParamId);
153+
154+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
155+
pub struct InternedOpaqueTyId(salsa::InternId);
156+
impl_intern_key!(InternedOpaqueTyId);

crates/ra_hir_ty/src/display.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fmt;
44

55
use crate::{
66
db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
7-
Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
7+
Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
88
};
99
use hir_def::{
1010
find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
@@ -359,6 +359,21 @@ impl HirDisplay for ApplicationTy {
359359
write!(f, ">")?;
360360
}
361361
}
362+
TypeCtor::OpaqueType(opaque_ty_id) => {
363+
let bounds = match opaque_ty_id {
364+
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
365+
let datas =
366+
f.db.return_type_impl_traits(func).expect("impl trait id without data");
367+
let data = (*datas)
368+
.as_ref()
369+
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
370+
data.clone().subst(&self.parameters)
371+
}
372+
};
373+
write!(f, "impl ")?;
374+
write_bounds_like_dyn_trait(&bounds.value, f)?;
375+
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
376+
}
362377
TypeCtor::Closure { .. } => {
363378
let sig = self.parameters[0].callable_sig(f.db);
364379
if let Some(sig) = sig {
@@ -427,14 +442,24 @@ impl HirDisplay for Ty {
427442
}
428443
}
429444
Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
430-
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
431-
match self {
432-
Ty::Dyn(_) => write!(f, "dyn ")?,
433-
Ty::Opaque(_) => write!(f, "impl ")?,
434-
_ => unreachable!(),
435-
};
445+
Ty::Dyn(predicates) => {
446+
write!(f, "dyn ")?;
436447
write_bounds_like_dyn_trait(predicates, f)?;
437448
}
449+
Ty::Opaque(opaque_ty) => {
450+
let bounds = match opaque_ty.opaque_ty_id {
451+
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
452+
let datas =
453+
f.db.return_type_impl_traits(func).expect("impl trait id without data");
454+
let data = (*datas)
455+
.as_ref()
456+
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
457+
data.clone().subst(&opaque_ty.parameters)
458+
}
459+
};
460+
write!(f, "impl ")?;
461+
write_bounds_like_dyn_trait(&bounds.value, f)?;
462+
}
438463
Ty::Unknown => write!(f, "{{unknown}}")?,
439464
Ty::Infer(..) => write!(f, "_")?,
440465
}

crates/ra_hir_ty/src/infer.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ use ra_syntax::SmolStr;
3939
use super::{
4040
primitive::{FloatTy, IntTy},
4141
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
42-
ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment,
43-
TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
42+
ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
43+
TypeWalk, Uncertain,
4444
};
4545
use crate::{
4646
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
@@ -383,25 +383,6 @@ impl<'a> InferenceContext<'a> {
383383
) -> Ty {
384384
match assoc_ty {
385385
Some(res_assoc_ty) => {
386-
// FIXME:
387-
// Check if inner_ty is is `impl Trait` and contained input TypeAlias id
388-
// this is a workaround while Chalk assoc type projection doesn't always work yet,
389-
// but once that is fixed I don't think we should keep this
390-
// (we'll probably change how associated types are resolved anyway)
391-
if let Ty::Opaque(ref predicates) = inner_ty {
392-
for p in predicates.iter() {
393-
if let GenericPredicate::Projection(projection) = p {
394-
if projection.projection_ty.associated_ty == res_assoc_ty {
395-
if let ty_app!(_, params) = &projection.ty {
396-
if params.len() == 0 {
397-
return projection.ty.clone();
398-
}
399-
}
400-
}
401-
}
402-
}
403-
}
404-
405386
let ty = self.table.new_type_var();
406387
let builder = Substs::build_for_def(self.db, res_assoc_ty)
407388
.push(inner_ty)

crates/ra_hir_ty/src/lib.rs

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ pub enum TypeCtor {
147147
/// an **application type** like `(Iterator::Item)<T>`.
148148
AssociatedType(TypeAliasId),
149149

150+
/// This represents a placeholder for an opaque type in situations where we
151+
/// don't know the hidden type (i.e. currently almost always). This is
152+
/// analogous to the `AssociatedType` type constructor. As with that one,
153+
/// these are only produced by Chalk.
154+
OpaqueType(OpaqueTyId),
155+
150156
/// The type of a specific closure.
151157
///
152158
/// The closure signature is stored in a `FnPtr` type in the first type
@@ -194,6 +200,14 @@ impl TypeCtor {
194200
let generic_params = generics(db.upcast(), type_alias.into());
195201
generic_params.len()
196202
}
203+
TypeCtor::OpaqueType(opaque_ty_id) => {
204+
match opaque_ty_id {
205+
OpaqueTyId::ReturnTypeImplTrait(func, _) => {
206+
let generic_params = generics(db.upcast(), func.into());
207+
generic_params.len()
208+
}
209+
}
210+
}
197211
TypeCtor::FnPtr { num_args } => num_args as usize + 1,
198212
TypeCtor::Tuple { cardinality } => cardinality as usize,
199213
}
@@ -220,6 +234,11 @@ impl TypeCtor {
220234
TypeCtor::AssociatedType(type_alias) => {
221235
Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate)
222236
}
237+
TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
238+
OpaqueTyId::ReturnTypeImplTrait(func, _) => {
239+
Some(func.lookup(db.upcast()).module(db.upcast()).krate)
240+
}
241+
},
223242
}
224243
}
225244

@@ -241,6 +260,7 @@ impl TypeCtor {
241260
TypeCtor::Adt(adt) => Some(adt.into()),
242261
TypeCtor::FnDef(callable) => Some(callable.into()),
243262
TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()),
263+
TypeCtor::OpaqueType(_impl_trait_id) => None,
244264
}
245265
}
246266
}
@@ -254,6 +274,12 @@ pub struct ApplicationTy {
254274
pub parameters: Substs,
255275
}
256276

277+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
278+
pub struct OpaqueTy {
279+
pub opaque_ty_id: OpaqueTyId,
280+
pub parameters: Substs,
281+
}
282+
257283
/// A "projection" type corresponds to an (unnormalized)
258284
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
259285
/// trait and all its parameters are fully known.
@@ -308,6 +334,12 @@ pub enum Ty {
308334
/// trait and all its parameters are fully known.
309335
Projection(ProjectionTy),
310336

337+
/// An opaque type (`impl Trait`).
338+
///
339+
/// This is currently only used for return type impl trait; each instance of
340+
/// `impl Trait` in a return type gets its own ID.
341+
Opaque(OpaqueTy),
342+
311343
/// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
312344
/// {}` when we're type-checking the body of that function. In this
313345
/// situation, we know this stands for *some* type, but don't know the exact
@@ -332,12 +364,6 @@ pub enum Ty {
332364
/// didn't seem worth the overhead yet.
333365
Dyn(Arc<[GenericPredicate]>),
334366

335-
/// An opaque type (`impl Trait`).
336-
///
337-
/// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
338-
/// more.
339-
Opaque(Arc<[GenericPredicate]>),
340-
341367
/// A placeholder for a type which could not be computed; this is propagated
342368
/// to avoid useless error messages. Doubles as a placeholder where type
343369
/// variables are inserted before type checking, since we want to try to
@@ -490,7 +516,7 @@ impl Deref for Substs {
490516
}
491517
}
492518

493-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
519+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
494520
pub struct Binders<T> {
495521
pub num_binders: usize,
496522
pub value: T,
@@ -534,6 +560,20 @@ impl<T: TypeWalk> Binders<T> {
534560
}
535561
}
536562

563+
impl<T: TypeWalk> TypeWalk for Binders<T> {
564+
fn walk(&self, f: &mut impl FnMut(&Ty)) {
565+
self.value.walk(f);
566+
}
567+
568+
fn walk_mut_binders(
569+
&mut self,
570+
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
571+
binders: DebruijnIndex,
572+
) {
573+
self.value.walk_mut_binders(f, binders.shifted_in())
574+
}
575+
}
576+
537577
/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
538578
/// Name to be bikeshedded: TraitBound? TraitImplements?
539579
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -947,11 +987,16 @@ impl TypeWalk for Ty {
947987
t.walk(f);
948988
}
949989
}
950-
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
990+
Ty::Dyn(predicates) => {
951991
for p in predicates.iter() {
952992
p.walk(f);
953993
}
954994
}
995+
Ty::Opaque(o_ty) => {
996+
for t in o_ty.parameters.iter() {
997+
t.walk(f);
998+
}
999+
}
9551000
Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
9561001
}
9571002
f(self);
@@ -969,13 +1014,48 @@ impl TypeWalk for Ty {
9691014
Ty::Projection(p_ty) => {
9701015
p_ty.parameters.walk_mut_binders(f, binders);
9711016
}
972-
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
1017+
Ty::Dyn(predicates) => {
9731018
for p in make_mut_slice(predicates) {
9741019
p.walk_mut_binders(f, binders.shifted_in());
9751020
}
9761021
}
1022+
Ty::Opaque(o_ty) => {
1023+
o_ty.parameters.walk_mut_binders(f, binders);
1024+
}
9771025
Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
9781026
}
9791027
f(self, binders);
9801028
}
9811029
}
1030+
1031+
impl<T: TypeWalk> TypeWalk for Vec<T> {
1032+
fn walk(&self, f: &mut impl FnMut(&Ty)) {
1033+
for t in self {
1034+
t.walk(f);
1035+
}
1036+
}
1037+
fn walk_mut_binders(
1038+
&mut self,
1039+
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1040+
binders: DebruijnIndex,
1041+
) {
1042+
for t in self {
1043+
t.walk_mut_binders(f, binders);
1044+
}
1045+
}
1046+
}
1047+
1048+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1049+
pub enum OpaqueTyId {
1050+
ReturnTypeImplTrait(hir_def::FunctionId, u16),
1051+
}
1052+
1053+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1054+
pub struct ReturnTypeImplTraits {
1055+
pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
1056+
}
1057+
1058+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1059+
pub(crate) struct ReturnTypeImplTrait {
1060+
pub(crate) bounds: Binders<Vec<GenericPredicate>>,
1061+
}

0 commit comments

Comments
 (0)