Implement TypeRef::ForLifetime

This commit is contained in:
Lukas Wirth 2021-06-30 01:34:51 +02:00
parent 1b9b2d1f40
commit af739731db
6 changed files with 64 additions and 19 deletions

View File

@ -2,6 +2,8 @@
use std::fmt::{self, Write};
use itertools::Itertools;
use crate::{
attr::RawAttrs,
generics::{WherePredicate, WherePredicateTypeTarget},
@ -542,6 +544,10 @@ impl<'a> Printer<'a> {
match bound.as_ref() {
TypeBound::Path(path) => self.print_path(path),
TypeBound::ForLifetime(lifetimes, path) => {
w!(self, "for<{}> ", lifetimes.iter().format(", "));
self.print_path(path);
}
TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
TypeBound::Error => w!(self, "{{unknown}}"),
}

View File

@ -282,6 +282,7 @@ struct S {
a: Mixed<'a, T, Item=(), OtherItem=u8>,
b: <Fully as Qualified>::Syntax,
c: <TypeAnchored>::Path::<'a>,
d: dyn for<'a> Trait<'a>,
}
"#,
expect![[r#"
@ -289,6 +290,7 @@ struct S {
pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
pub(self) b: Qualified<Self=Fully>::Syntax,
pub(self) c: <TypeAnchored>::Path<'a>,
pub(self) d: dyn for<'a> Trait<'a>,
}
"#]],
)
@ -311,7 +313,7 @@ impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
enum Enum<'a, T, const U: u8> {}
union Union<'a, T, const U: u8> {}
trait Tr<'a, T: 'a>: Super {}
trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
"#,
expect![[r#"
pub(self) struct S<'a, 'b, T, const K: u8>
@ -353,7 +355,8 @@ trait Tr<'a, T: 'a>: Super {}
pub(self) trait Tr<'a, Self, T>
where
Self: Super,
T: 'a
T: 'a,
Self: for<'a> Tr<'a, T>
{
}
"#]],

View File

@ -119,7 +119,7 @@ impl LifetimeRef {
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeBound {
Path(Path),
// ForLifetime(Vec<LifetimeRef>, Path), FIXME ForLifetime
ForLifetime(Box<[Name]>, Path),
Lifetime(LifetimeRef),
Error,
}
@ -233,7 +233,9 @@ impl TypeRef {
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
match bound.as_ref() {
TypeBound::Path(path) => go_path(path, f),
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)
}
TypeBound::Lifetime(_) | TypeBound::Error => (),
}
}
@ -263,7 +265,9 @@ impl TypeRef {
}
for bound in &binding.bounds {
match bound.as_ref() {
TypeBound::Path(path) => go_path(path, f),
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)
}
TypeBound::Lifetime(_) | TypeBound::Error => (),
}
}
@ -287,20 +291,29 @@ pub(crate) fn type_bounds_from_ast(
impl TypeBound {
pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
let lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
match node.kind() {
ast::TypeBoundKind::PathType(path_type) => {
let path = match path_type.path() {
Some(p) => p,
None => return TypeBound::Error,
};
let path = match ctx.lower_path(path) {
Some(p) => p,
None => return TypeBound::Error,
};
TypeBound::Path(path)
lower_path_type(path_type).map(TypeBound::Path).unwrap_or(TypeBound::Error)
}
ast::TypeBoundKind::ForType(for_type) => {
let lt_refs = match for_type.generic_param_list() {
Some(gpl) => gpl
.lifetime_params()
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt)))
.collect(),
None => Box::default(),
};
let path = for_type.ty().and_then(|ty| match ty {
ast::Type::PathType(path_type) => lower_path_type(path_type),
_ => None,
});
match path {
Some(p) => TypeBound::ForLifetime(lt_refs, p),
None => TypeBound::Error,
}
}
ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
ast::TypeBoundKind::Lifetime(lifetime) => {
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
}
@ -309,8 +322,8 @@ impl TypeBound {
pub fn as_path(&self) -> Option<&Path> {
match self {
TypeBound::Path(p) => Some(p),
_ => None,
TypeBound::Path(p) | TypeBound::ForLifetime(_, p) => Some(p),
TypeBound::Lifetime(_) | TypeBound::Error => None,
}
}
}

View File

@ -21,6 +21,7 @@ use hir_def::{
AssocContainerId, Lookup, ModuleId, TraitId,
};
use hir_expand::{hygiene::Hygiene, name::Name};
use itertools::Itertools;
use crate::{
const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
@ -1029,6 +1030,10 @@ impl HirDisplay for TypeBound {
match self {
TypeBound::Path(path) => path.hir_fmt(f),
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
TypeBound::ForLifetime(lifetimes, path) => {
write!(f, "for<{}> ", lifetimes.iter().format(", "))?;
path.hir_fmt(f)
}
TypeBound::Error => write!(f, "{{error}}"),
}
}

View File

@ -786,6 +786,11 @@ impl<'a> TyLoweringContext<'a> {
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
}
TypeBound::ForLifetime(_, path) => {
// FIXME Don't silently drop the hrtb lifetimes here
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
}
TypeBound::Lifetime(_) => None,
TypeBound::Error => None,
};
@ -803,7 +808,7 @@ impl<'a> TyLoweringContext<'a> {
trait_ref: TraitRef,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let last_segment = match bound {
TypeBound::Path(path) => path.segments().last(),
TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => path.segments().last(),
TypeBound::Error | TypeBound::Lifetime(_) => None,
};
last_segment

View File

@ -54,3 +54,16 @@ fn main() {
"#,
);
}
#[test]
fn render_dyn_for_ty() {
// FIXME
check_types_source_code(
r#"
trait Foo<'a> {}
fn foo(foo: &dyn for<'a> Foo<'a>) {}
// ^^^ &dyn Foo
"#,
);
}