mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 02:03:53 +00:00
Add impl Trait
and dyn Trait
types
- refactor bounds handling in the AST a bit - add HIR for bounds - add `Ty::Dyn` and `Ty::Opaque` variants and lower `dyn Trait` / `impl Trait` syntax to them
This commit is contained in:
parent
08e5d394df
commit
16a7d8cc85
@ -11,7 +11,7 @@ use crate::{
|
||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||
name::SELF_TYPE,
|
||||
path::Path,
|
||||
type_ref::TypeRef,
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
|
||||
Trait, TypeAlias, Union,
|
||||
};
|
||||
@ -35,10 +35,12 @@ pub struct GenericParams {
|
||||
|
||||
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
||||
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
|
||||
/// It might still result in multiple actual predicates though, because of
|
||||
/// associated type bindings like `Iterator<Item = u32>`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct WherePredicate {
|
||||
pub(crate) type_ref: TypeRef,
|
||||
pub(crate) trait_ref: Path,
|
||||
pub(crate) bound: TypeBound,
|
||||
}
|
||||
|
||||
// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
|
||||
@ -143,18 +145,8 @@ impl GenericParams {
|
||||
// FIXME: remove this bound
|
||||
return;
|
||||
}
|
||||
let path = bound
|
||||
.type_ref()
|
||||
.and_then(|tr| match tr {
|
||||
ast::TypeRef::PathType(path) => path.path(),
|
||||
_ => None,
|
||||
})
|
||||
.and_then(Path::from_ast);
|
||||
let path = match path {
|
||||
Some(p) => p,
|
||||
None => return,
|
||||
};
|
||||
self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
|
||||
let bound = TypeBound::from_ast(bound);
|
||||
self.where_predicates.push(WherePredicate { type_ref, bound });
|
||||
}
|
||||
|
||||
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
|
||||
|
@ -161,14 +161,28 @@ pub enum Ty {
|
||||
name: Name,
|
||||
},
|
||||
|
||||
/// A bound type variable. Only used during trait resolution to represent
|
||||
/// Chalk variables.
|
||||
/// A bound type variable. Used during trait resolution to represent Chalk
|
||||
/// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type.
|
||||
Bound(u32),
|
||||
|
||||
/// A type variable used during type checking. Not to be confused with a
|
||||
/// type parameter.
|
||||
Infer(InferTy),
|
||||
|
||||
/// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
|
||||
///
|
||||
/// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
|
||||
/// represents the `Self` type inside the bounds. This is currently
|
||||
/// implicit; Chalk has the `Binders` struct to make it explicit, but it
|
||||
/// didn't seem worth the overhead yet.
|
||||
Dyn(Arc<[GenericPredicate]>),
|
||||
|
||||
/// An opaque type (`impl Trait`).
|
||||
///
|
||||
/// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
|
||||
/// more.
|
||||
Opaque(Arc<[GenericPredicate]>),
|
||||
|
||||
/// A placeholder for a type which could not be computed; this is propagated
|
||||
/// to avoid useless error messages. Doubles as a placeholder where type
|
||||
/// variables are inserted before type checking, since we want to try to
|
||||
@ -194,6 +208,12 @@ impl Substs {
|
||||
Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into())
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
for t in self.0.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||
let mut v: Vec<_> = self.0.iter().cloned().collect();
|
||||
@ -270,6 +290,14 @@ impl TraitRef {
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
self.substs.walk(f);
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
self.substs.walk_mut(f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
|
||||
@ -299,6 +327,20 @@ impl GenericPredicate {
|
||||
GenericPredicate::Error => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||
match self {
|
||||
GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
|
||||
GenericPredicate::Error => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
match self {
|
||||
GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
|
||||
GenericPredicate::Error => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Basically a claim (currently not validated / checked) that the contained
|
||||
@ -386,6 +428,11 @@ impl Ty {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
for p in predicates.iter() {
|
||||
p.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
@ -402,6 +449,13 @@ impl Ty {
|
||||
Ty::UnselectedProjection(p_ty) => {
|
||||
p_ty.parameters.walk_mut(f);
|
||||
}
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
let mut v: Vec<_> = predicates.iter().cloned().collect();
|
||||
for p in &mut v {
|
||||
p.walk_mut(f);
|
||||
}
|
||||
*predicates = v.into();
|
||||
}
|
||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
@ -669,6 +723,28 @@ impl HirDisplay for Ty {
|
||||
Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?,
|
||||
Ty::Param { name, .. } => write!(f, "{}", name)?,
|
||||
Ty::Bound(idx) => write!(f, "?{}", idx)?,
|
||||
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||
match self {
|
||||
Ty::Dyn(_) => write!(f, "dyn ")?,
|
||||
Ty::Opaque(_) => write!(f, "impl ")?,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// looping by hand here just to format the bounds in a slightly nicer way
|
||||
let mut first = true;
|
||||
for p in predicates.iter() {
|
||||
if !first {
|
||||
write!(f, " + ")?;
|
||||
}
|
||||
first = false;
|
||||
match p {
|
||||
// don't show the $0 self type
|
||||
GenericPredicate::Implemented(trait_ref) => {
|
||||
trait_ref.hir_fmt_ext(f, false)?
|
||||
}
|
||||
GenericPredicate::Error => p.hir_fmt(f)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
Ty::Unknown => write!(f, "{{unknown}}")?,
|
||||
Ty::Infer(..) => write!(f, "_")?,
|
||||
}
|
||||
@ -676,14 +752,16 @@ impl HirDisplay for Ty {
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TraitRef {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}: {}",
|
||||
self.substs[0].display(f.db),
|
||||
self.trait_.name(f.db).unwrap_or_else(Name::missing)
|
||||
)?;
|
||||
impl TraitRef {
|
||||
fn hir_fmt_ext(
|
||||
&self,
|
||||
f: &mut HirFormatter<impl HirDatabase>,
|
||||
with_self_ty: bool,
|
||||
) -> fmt::Result {
|
||||
if with_self_ty {
|
||||
write!(f, "{}: ", self.substs[0].display(f.db),)?;
|
||||
}
|
||||
write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
|
||||
if self.substs.len() > 1 {
|
||||
write!(f, "<")?;
|
||||
f.write_joined(&self.substs[1..], ", ")?;
|
||||
@ -693,6 +771,28 @@ impl HirDisplay for TraitRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TraitRef {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
self.hir_fmt_ext(f, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for &GenericPredicate {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
HirDisplay::hir_fmt(*self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for GenericPredicate {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
match self {
|
||||
GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
|
||||
GenericPredicate::Error => write!(f, "{{error}}")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Obligation {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||
path::{GenericArg, PathSegment},
|
||||
resolve::{Resolution, Resolver},
|
||||
ty::AdtDef,
|
||||
type_ref::TypeRef,
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct,
|
||||
StructField, Trait, TypeAlias, Union,
|
||||
};
|
||||
@ -58,6 +58,22 @@ impl Ty {
|
||||
let sig = Substs(inner_tys.into());
|
||||
Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
let self_ty = Ty::Bound(0);
|
||||
let predicates = bounds
|
||||
.iter()
|
||||
.map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
Ty::Dyn(predicates.into())
|
||||
}
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
let self_ty = Ty::Bound(0);
|
||||
let predicates = bounds
|
||||
.iter()
|
||||
.map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
Ty::Opaque(predicates.into())
|
||||
}
|
||||
TypeRef::Error => Ty::Unknown,
|
||||
}
|
||||
}
|
||||
@ -310,13 +326,46 @@ impl TraitRef {
|
||||
TraitRef { trait_, substs }
|
||||
}
|
||||
|
||||
pub(crate) fn for_where_predicate(
|
||||
pub(crate) fn from_where_predicate(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
pred: &WherePredicate,
|
||||
) -> Option<TraitRef> {
|
||||
let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
|
||||
TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty))
|
||||
TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
|
||||
}
|
||||
|
||||
pub(crate) fn from_type_bound(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
bound: &TypeBound,
|
||||
self_ty: Ty,
|
||||
) -> Option<TraitRef> {
|
||||
match bound {
|
||||
TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)),
|
||||
TypeBound::Error => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericPredicate {
|
||||
pub(crate) fn from_where_predicate(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
where_predicate: &WherePredicate,
|
||||
) -> GenericPredicate {
|
||||
TraitRef::from_where_predicate(db, &resolver, where_predicate)
|
||||
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||
}
|
||||
|
||||
pub(crate) fn from_type_bound(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
bound: &TypeBound,
|
||||
self_ty: Ty,
|
||||
) -> GenericPredicate {
|
||||
TraitRef::from_type_bound(db, &resolver, bound, self_ty)
|
||||
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,10 +425,7 @@ pub(crate) fn trait_env(
|
||||
) -> Arc<super::TraitEnvironment> {
|
||||
let predicates = resolver
|
||||
.where_predicates_in_scope()
|
||||
.map(|pred| {
|
||||
TraitRef::for_where_predicate(db, &resolver, pred)
|
||||
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||
})
|
||||
.map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Arc::new(super::TraitEnvironment { predicates })
|
||||
@ -393,10 +439,7 @@ pub(crate) fn generic_predicates_query(
|
||||
let resolver = def.resolver(db);
|
||||
let predicates = resolver
|
||||
.where_predicates_in_scope()
|
||||
.map(|pred| {
|
||||
TraitRef::for_where_predicate(db, &resolver, pred)
|
||||
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||
})
|
||||
.map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
|
||||
.collect::<Vec<_>>();
|
||||
predicates.into()
|
||||
}
|
||||
|
@ -3273,6 +3273,126 @@ fn test<T: ApplyL>(t: T) {
|
||||
assert_eq!(t, "{unknown}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn impl_trait() {
|
||||
assert_snapshot_matches!(
|
||||
infer(r#"
|
||||
trait Trait<T> {
|
||||
fn foo(&self) -> T;
|
||||
}
|
||||
fn bar() -> impl Trait<u64> {}
|
||||
|
||||
fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
|
||||
x;
|
||||
y;
|
||||
let z = bar();
|
||||
x.foo();
|
||||
y.foo();
|
||||
z.foo();
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
⋮
|
||||
⋮[30; 34) 'self': &Self
|
||||
⋮[72; 74) '{}': ()
|
||||
⋮[84; 85) 'x': impl Trait<u64>
|
||||
⋮[104; 105) 'y': &impl Trait<u64>
|
||||
⋮[125; 200) '{ ...o(); }': ()
|
||||
⋮[131; 132) 'x': impl Trait<u64>
|
||||
⋮[138; 139) 'y': &impl Trait<u64>
|
||||
⋮[149; 150) 'z': impl Trait<u64>
|
||||
⋮[153; 156) 'bar': fn bar() -> impl Trait<u64>
|
||||
⋮[153; 158) 'bar()': impl Trait<u64>
|
||||
⋮[164; 165) 'x': impl Trait<u64>
|
||||
⋮[164; 171) 'x.foo()': {unknown}
|
||||
⋮[177; 178) 'y': &impl Trait<u64>
|
||||
⋮[177; 184) 'y.foo()': {unknown}
|
||||
⋮[190; 191) 'z': impl Trait<u64>
|
||||
⋮[190; 197) 'z.foo()': {unknown}
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dyn_trait() {
|
||||
assert_snapshot_matches!(
|
||||
infer(r#"
|
||||
trait Trait<T> {
|
||||
fn foo(&self) -> T;
|
||||
}
|
||||
fn bar() -> dyn Trait<u64> {}
|
||||
|
||||
fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
|
||||
x;
|
||||
y;
|
||||
let z = bar();
|
||||
x.foo();
|
||||
y.foo();
|
||||
z.foo();
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
⋮
|
||||
⋮[30; 34) 'self': &Self
|
||||
⋮[71; 73) '{}': ()
|
||||
⋮[83; 84) 'x': dyn Trait<u64>
|
||||
⋮[102; 103) 'y': &dyn Trait<u64>
|
||||
⋮[122; 197) '{ ...o(); }': ()
|
||||
⋮[128; 129) 'x': dyn Trait<u64>
|
||||
⋮[135; 136) 'y': &dyn Trait<u64>
|
||||
⋮[146; 147) 'z': dyn Trait<u64>
|
||||
⋮[150; 153) 'bar': fn bar() -> dyn Trait<u64>
|
||||
⋮[150; 155) 'bar()': dyn Trait<u64>
|
||||
⋮[161; 162) 'x': dyn Trait<u64>
|
||||
⋮[161; 168) 'x.foo()': {unknown}
|
||||
⋮[174; 175) 'y': &dyn Trait<u64>
|
||||
⋮[174; 181) 'y.foo()': {unknown}
|
||||
⋮[187; 188) 'z': dyn Trait<u64>
|
||||
⋮[187; 194) 'z.foo()': {unknown}
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dyn_trait_bare() {
|
||||
assert_snapshot_matches!(
|
||||
infer(r#"
|
||||
trait Trait {
|
||||
fn foo(&self) -> u64;
|
||||
}
|
||||
fn bar() -> Trait {}
|
||||
|
||||
fn test(x: Trait, y: &Trait) -> u64 {
|
||||
x;
|
||||
y;
|
||||
let z = bar();
|
||||
x.foo();
|
||||
y.foo();
|
||||
z.foo();
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
⋮
|
||||
⋮[27; 31) 'self': &Self
|
||||
⋮[61; 63) '{}': ()
|
||||
⋮[73; 74) 'x': {unknown}
|
||||
⋮[83; 84) 'y': &{unknown}
|
||||
⋮[101; 176) '{ ...o(); }': ()
|
||||
⋮[107; 108) 'x': {unknown}
|
||||
⋮[114; 115) 'y': &{unknown}
|
||||
⋮[125; 126) 'z': {unknown}
|
||||
⋮[129; 132) 'bar': fn bar() -> {unknown}
|
||||
⋮[129; 134) 'bar()': {unknown}
|
||||
⋮[140; 141) 'x': {unknown}
|
||||
⋮[140; 147) 'x.foo()': {unknown}
|
||||
⋮[153; 154) 'y': &{unknown}
|
||||
⋮[153; 160) 'y.foo()': {unknown}
|
||||
⋮[166; 167) 'z': {unknown}
|
||||
⋮[166; 173) 'z.foo()': {unknown}
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||
let file = db.parse(pos.file_id).ok().unwrap();
|
||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||
|
@ -80,7 +80,9 @@ impl ToChalk for Ty {
|
||||
// FIXME this is clearly incorrect, but probably not too incorrect
|
||||
// and I'm not sure what to actually do with Ty::Unknown
|
||||
// maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
|
||||
Ty::Unknown => {
|
||||
//
|
||||
// FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet
|
||||
Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
|
||||
PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! HIR for references to types. Paths in these are not yet resolved. They can
|
||||
//! be directly created from an ast::TypeRef, without further queries.
|
||||
|
||||
use ra_syntax::ast::{self, TypeAscriptionOwner};
|
||||
use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner};
|
||||
|
||||
use crate::Path;
|
||||
|
||||
@ -49,8 +49,16 @@ pub enum TypeRef {
|
||||
/// A fn pointer. Last element of the vector is the return type.
|
||||
Fn(Vec<TypeRef>),
|
||||
// For
|
||||
// ImplTrait,
|
||||
// DynTrait,
|
||||
ImplTrait(Vec<TypeBound>),
|
||||
DynTrait(Vec<TypeBound>),
|
||||
Error,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum TypeBound {
|
||||
Path(Path),
|
||||
// also for<> bounds
|
||||
// also Lifetimes
|
||||
Error,
|
||||
}
|
||||
|
||||
@ -95,8 +103,12 @@ impl TypeRef {
|
||||
}
|
||||
// for types are close enough for our purposes to the inner type for now...
|
||||
ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
|
||||
ast::TypeRef::ImplTraitType(_inner) => TypeRef::Error,
|
||||
ast::TypeRef::DynTraitType(_inner) => TypeRef::Error,
|
||||
ast::TypeRef::ImplTraitType(inner) => {
|
||||
TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list()))
|
||||
}
|
||||
ast::TypeRef::DynTraitType(inner) => {
|
||||
TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,3 +124,32 @@ impl TypeRef {
|
||||
TypeRef::Tuple(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
|
||||
if let Some(type_bounds) = type_bounds_opt {
|
||||
type_bounds.bounds().map(TypeBound::from_ast).collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeBound {
|
||||
pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
|
||||
match node.kind() {
|
||||
Some(ast::TypeBoundKind::PathType(path_type)) => {
|
||||
let path = match path_type.path() {
|
||||
Some(p) => p,
|
||||
None => return TypeBound::Error,
|
||||
};
|
||||
let path = match Path::from_ast(path) {
|
||||
Some(p) => p,
|
||||
None => return TypeBound::Error,
|
||||
};
|
||||
TypeBound::Path(path)
|
||||
}
|
||||
Some(ast::TypeBoundKind::ForType(_)) | Some(ast::TypeBoundKind::Lifetime(_)) | None => {
|
||||
TypeBound::Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
|
||||
pub use self::{
|
||||
expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp},
|
||||
extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind},
|
||||
extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind},
|
||||
generated::*,
|
||||
tokens::*,
|
||||
traits::*,
|
||||
|
@ -399,3 +399,29 @@ impl ast::TraitDef {
|
||||
self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum TypeBoundKind {
|
||||
/// Trait
|
||||
PathType(ast::PathType),
|
||||
/// for<'a> ...
|
||||
ForType(ast::ForType),
|
||||
/// 'a
|
||||
Lifetime(ast::SyntaxToken),
|
||||
}
|
||||
|
||||
impl ast::TypeBound {
|
||||
pub fn kind(&self) -> Option<TypeBoundKind> {
|
||||
let child = self.syntax.first_child_or_token()?;
|
||||
match child.kind() {
|
||||
PATH_TYPE => Some(TypeBoundKind::PathType(
|
||||
ast::PathType::cast(child.into_node().unwrap()).unwrap(),
|
||||
)),
|
||||
FOR_TYPE => Some(TypeBoundKind::ForType(
|
||||
ast::ForType::cast(child.into_node().unwrap()).unwrap(),
|
||||
)),
|
||||
LIFETIME => Some(TypeBoundKind::Lifetime(child.into_token().unwrap())),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user