mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Implement TypeRef::ForLifetime
This commit is contained in:
parent
1b9b2d1f40
commit
af739731db
6 changed files with 64 additions and 19 deletions
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::RawAttrs,
|
attr::RawAttrs,
|
||||||
generics::{WherePredicate, WherePredicateTypeTarget},
|
generics::{WherePredicate, WherePredicateTypeTarget},
|
||||||
|
@ -542,6 +544,10 @@ impl<'a> Printer<'a> {
|
||||||
|
|
||||||
match bound.as_ref() {
|
match bound.as_ref() {
|
||||||
TypeBound::Path(path) => self.print_path(path),
|
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::Lifetime(lt) => w!(self, "{}", lt.name),
|
||||||
TypeBound::Error => w!(self, "{{unknown}}"),
|
TypeBound::Error => w!(self, "{{unknown}}"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,6 +282,7 @@ struct S {
|
||||||
a: Mixed<'a, T, Item=(), OtherItem=u8>,
|
a: Mixed<'a, T, Item=(), OtherItem=u8>,
|
||||||
b: <Fully as Qualified>::Syntax,
|
b: <Fully as Qualified>::Syntax,
|
||||||
c: <TypeAnchored>::Path::<'a>,
|
c: <TypeAnchored>::Path::<'a>,
|
||||||
|
d: dyn for<'a> Trait<'a>,
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
@ -289,6 +290,7 @@ struct S {
|
||||||
pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
|
pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
|
||||||
pub(self) b: Qualified<Self=Fully>::Syntax,
|
pub(self) b: Qualified<Self=Fully>::Syntax,
|
||||||
pub(self) c: <TypeAnchored>::Path<'a>,
|
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> {}
|
enum Enum<'a, T, const U: u8> {}
|
||||||
union Union<'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#"
|
expect![[r#"
|
||||||
pub(self) struct S<'a, 'b, T, const K: u8>
|
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>
|
pub(self) trait Tr<'a, Self, T>
|
||||||
where
|
where
|
||||||
Self: Super,
|
Self: Super,
|
||||||
T: 'a
|
T: 'a,
|
||||||
|
Self: for<'a> Tr<'a, T>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
"#]],
|
"#]],
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl LifetimeRef {
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum TypeBound {
|
pub enum TypeBound {
|
||||||
Path(Path),
|
Path(Path),
|
||||||
// ForLifetime(Vec<LifetimeRef>, Path), FIXME ForLifetime
|
ForLifetime(Box<[Name]>, Path),
|
||||||
Lifetime(LifetimeRef),
|
Lifetime(LifetimeRef),
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,9 @@ impl TypeRef {
|
||||||
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
match bound.as_ref() {
|
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 => (),
|
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,7 +265,9 @@ impl TypeRef {
|
||||||
}
|
}
|
||||||
for bound in &binding.bounds {
|
for bound in &binding.bounds {
|
||||||
match bound.as_ref() {
|
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 => (),
|
TypeBound::Lifetime(_) | TypeBound::Error => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,20 +291,29 @@ pub(crate) fn type_bounds_from_ast(
|
||||||
|
|
||||||
impl TypeBound {
|
impl TypeBound {
|
||||||
pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
|
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() {
|
match node.kind() {
|
||||||
ast::TypeBoundKind::PathType(path_type) => {
|
ast::TypeBoundKind::PathType(path_type) => {
|
||||||
let path = match path_type.path() {
|
lower_path_type(path_type).map(TypeBound::Path).unwrap_or(TypeBound::Error)
|
||||||
Some(p) => p,
|
}
|
||||||
None => return TypeBound::Error,
|
ast::TypeBoundKind::ForType(for_type) => {
|
||||||
};
|
let lt_refs = match for_type.generic_param_list() {
|
||||||
|
Some(gpl) => gpl
|
||||||
let path = match ctx.lower_path(path) {
|
.lifetime_params()
|
||||||
Some(p) => p,
|
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<)))
|
||||||
None => return TypeBound::Error,
|
.collect(),
|
||||||
};
|
None => Box::default(),
|
||||||
TypeBound::Path(path)
|
};
|
||||||
|
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) => {
|
ast::TypeBoundKind::Lifetime(lifetime) => {
|
||||||
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
|
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
|
||||||
}
|
}
|
||||||
|
@ -309,8 +322,8 @@ impl TypeBound {
|
||||||
|
|
||||||
pub fn as_path(&self) -> Option<&Path> {
|
pub fn as_path(&self) -> Option<&Path> {
|
||||||
match self {
|
match self {
|
||||||
TypeBound::Path(p) => Some(p),
|
TypeBound::Path(p) | TypeBound::ForLifetime(_, p) => Some(p),
|
||||||
_ => None,
|
TypeBound::Lifetime(_) | TypeBound::Error => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ use hir_def::{
|
||||||
AssocContainerId, Lookup, ModuleId, TraitId,
|
AssocContainerId, Lookup, ModuleId, TraitId,
|
||||||
};
|
};
|
||||||
use hir_expand::{hygiene::Hygiene, name::Name};
|
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
|
const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
|
||||||
|
@ -1029,6 +1030,10 @@ impl HirDisplay for TypeBound {
|
||||||
match self {
|
match self {
|
||||||
TypeBound::Path(path) => path.hir_fmt(f),
|
TypeBound::Path(path) => path.hir_fmt(f),
|
||||||
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
|
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}}"),
|
TypeBound::Error => write!(f, "{{error}}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -786,6 +786,11 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
|
bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
|
||||||
bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
|
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::Lifetime(_) => None,
|
||||||
TypeBound::Error => None,
|
TypeBound::Error => None,
|
||||||
};
|
};
|
||||||
|
@ -803,7 +808,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
trait_ref: TraitRef,
|
trait_ref: TraitRef,
|
||||||
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
|
||||||
let last_segment = match bound {
|
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,
|
TypeBound::Error | TypeBound::Lifetime(_) => None,
|
||||||
};
|
};
|
||||||
last_segment
|
last_segment
|
||||||
|
|
|
@ -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
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue