//! 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 hir_expand::name::Name;
-use syntax::{ast, SyntaxToken};
+
+use hir_expand::{name::Name, AstId, InFile};
+use std::convert::TryInto;
+use syntax::ast;
use crate::{body::LowerCtx, path::Path};
}
}
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct TraitRef {
+ pub path: Path,
+}
+
+impl TraitRef {
+ /// Converts an `ast::PathType` to a `hir::TraitRef`.
+ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> {
+ // FIXME: Use `Path::from_src`
+ match node {
+ ast::Type::PathType(path) => {
+ path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
+ }
+ _ => None,
+ }
+ }
+}
+
/// Compare ty::Ty
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef {
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
- Array(Box<TypeRef> /*, Expr*/),
+ Array(Box<TypeRef>, ConstScalar),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<TypeRef>, bool /*varargs*/),
// For
ImplTrait(Vec<TypeBound>),
DynTrait(Vec<TypeBound>),
+ Macro(AstId<ast::MacroCall>),
Error,
}
LifetimeRef { name }
}
- pub(crate) fn from_token(token: SyntaxToken) -> Self {
- LifetimeRef { name: Name::new_lifetime(&token) }
+ pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
+ LifetimeRef { name: Name::new_lifetime(lifetime) }
}
pub fn missing() -> LifetimeRef {
impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
- pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
+ pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
match node {
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
ast::Type::TupleType(inner) => {
TypeRef::RawPtr(Box::new(inner_ty), mutability)
}
ast::Type::ArrayType(inner) => {
- TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
+ let len = inner
+ .expr()
+ .map(ConstScalar::usize_from_literal_expr)
+ .unwrap_or(ConstScalar::Unknown);
+
+ TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len)
}
ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
}
ast::Type::RefType(inner) => {
let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
- let lifetime = inner.lifetime_token().map(|t| LifetimeRef::from_token(t));
+ let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<));
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
}
ast::Type::DynTraitType(inner) => {
TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
}
+ ast::Type::MacroType(mt) => match mt.macro_call() {
+ Some(mc) => ctx
+ .ast_id(&mc)
+ .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
+ .unwrap_or(TypeRef::Error),
+ None => TypeRef::Error,
+ },
}
}
}
TypeRef::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..)
- | TypeRef::Array(type_ref)
+ | TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(&type_ref, f),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
}
}
TypeRef::Path(path) => go_path(path, f),
- TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
+ TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
};
}
}
ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
ast::TypeBoundKind::Lifetime(lifetime) => {
- TypeBound::Lifetime(LifetimeRef::from_token(lifetime))
+ TypeBound::Lifetime(LifetimeRef::new(&lifetime))
}
}
}
}
}
}
+
+/// A concrete constant value
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ConstScalar {
+ // for now, we only support the trivial case of constant evaluating the length of an array
+ // Note that this is u64 because the target usize may be bigger than our usize
+ Usize(u64),
+
+ /// Case of an unknown value that rustc might know but we don't
+ Unknown,
+}
+
+impl std::fmt::Display for ConstScalar {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ match self {
+ ConstScalar::Usize(us) => write!(fmt, "{}", us),
+ ConstScalar::Unknown => write!(fmt, "_"),
+ }
+ }
+}
+
+impl ConstScalar {
+ fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
+ match expr {
+ ast::Expr::Literal(lit) => {
+ let lkind = lit.kind();
+ match lkind {
+ ast::LiteralKind::IntNumber(num)
+ if num.suffix() == None || num.suffix() == Some("usize") =>
+ {
+ num.value().and_then(|v| v.try_into().ok())
+ }
+ _ => None,
+ }
+ }
+ _ => None,
+ }
+ .map(ConstScalar::Usize)
+ .unwrap_or(ConstScalar::Unknown)
+ }
+}