diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index 8b12e5a67cb..603c594f2aa 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs @@ -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}}"), } diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index 57686dc6e7c..cbaa6d086db 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs @@ -282,6 +282,7 @@ struct S { a: Mixed<'a, T, Item=(), OtherItem=u8>, b: ::Syntax, c: ::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::Syntax, pub(self) c: ::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> { } "#]], diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index ffe4999738a..1d35f02ca1d 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs @@ -119,7 +119,7 @@ impl LifetimeRef { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeBound { Path(Path), - // ForLifetime(Vec, 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(<))) + .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, } } } diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 44f843bf383..946ff1073e4 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -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}}"), } } diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index ea03b6a6c5e..239ac3786e7 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -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 + '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 diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs index 058cd02d7a7..a484dc3a03b 100644 --- a/crates/hir_ty/src/tests/display_source_code.rs +++ b/crates/hir_ty/src/tests/display_source_code.rs @@ -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 +"#, + ); +}