diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs index 66e4634b1d3..da94e9987c6 100644 --- a/crates/assists/src/ast_transform.rs +++ b/crates/assists/src/ast_transform.rs @@ -89,7 +89,7 @@ impl<'a> SubstituteTypeParams<'a> { let substs = get_syntactic_substs(impl_def).unwrap_or_default(); let generic_def: hir::GenericDef = trait_.into(); let substs_by_param: FxHashMap<_, _> = generic_def - .params(source_scope.db) + .type_params(source_scope.db) .into_iter() // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky .skip(1) diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 9a1e9ba496b..fcc42c6bbc4 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -19,8 +19,9 @@ use hir_def::{ src::HasSource as _, type_ref::{Mutability, TypeRef}, AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId, - FunctionId, GenericDefId, HasModule, ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, - Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, + FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, + LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, + UnionId, }; use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; use hir_expand::{ @@ -831,7 +832,7 @@ impl SelfParam { .params .first() .map(|param| match *param { - TypeRef::Reference(_, mutability) => mutability.into(), + TypeRef::Reference(.., mutability) => mutability.into(), _ => Access::Owned, }) .unwrap_or(Access::Owned) @@ -1098,8 +1099,25 @@ impl_from!( ); impl GenericDef { - pub fn params(self, db: &dyn HirDatabase) -> Vec { - let generics: Arc = db.generic_params(self.into()); + pub fn params(self, db: &dyn HirDatabase) -> Vec { + let generics = db.generic_params(self.into()); + let ty_params = generics + .types + .iter() + .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) + .map(GenericParam::TypeParam); + let lt_params = generics + .lifetimes + .iter() + .map(|(local_id, _)| LifetimeParam { + id: LifetimeParamId { parent: self.into(), local_id }, + }) + .map(GenericParam::LifetimeParam); + ty_params.chain(lt_params).collect() + } + + pub fn type_params(self, db: &dyn HirDatabase) -> Vec { + let generics = db.generic_params(self.into()); generics .types .iter() @@ -1175,6 +1193,13 @@ impl Local { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum GenericParam { + TypeParam(TypeParam), + LifetimeParam(LifetimeParam), +} +impl_from!(TypeParam, LifetimeParam for GenericParam); + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct TypeParam { pub(crate) id: TypeParamId, @@ -1215,6 +1240,18 @@ impl TypeParam { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct LifetimeParam { + pub(crate) id: LifetimeParamId, +} + +impl LifetimeParam { + pub fn name(self, db: &dyn HirDatabase) -> Name { + let params = db.generic_params(self.id.parent); + params.lifetimes[self.id.local_id].name.clone() + } +} + // FIXME: rename from `ImplDef` to `Impl` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ImplDef { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 302a524918a..0f399a2c6ec 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -35,8 +35,8 @@ pub use crate::{ code_model::{ Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function, - GenericDef, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, - Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, + GenericDef, HasVisibility, ImplDef, LifetimeParam, Local, MacroDef, Module, ModuleDef, + ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, }, has_source::HasSource, semantics::{PathResolution, Semantics, SemanticsScope}, @@ -56,8 +56,9 @@ pub use hir_def::{ visibility::Visibility, }; pub use hir_expand::{ - name::known, name::AsName, name::Name, ExpandResult, HirFileId, InFile, MacroCallId, - MacroCallLoc, /* FIXME */ MacroDefId, MacroFile, Origin, + name::{known, AsName, Name}, + ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, + MacroFile, Origin, }; pub use hir_ty::display::HirDisplay; diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 835fe3fbdc6..5189c7e9f38 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs @@ -21,7 +21,7 @@ use crate::{ keys, src::HasChildSource, src::HasSource, - type_ref::{TypeBound, TypeRef}, + type_ref::{LifetimeRef, TypeBound, TypeRef}, AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, }; @@ -33,6 +33,12 @@ pub struct TypeParamData { pub provenance: TypeParamProvenance, } +/// Data about a generic parameter (to a function, struct, impl, ...). +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LifetimeParamData { + pub name: Name, +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum TypeParamProvenance { TypeParamList, @@ -44,7 +50,7 @@ pub enum TypeParamProvenance { #[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct GenericParams { pub types: Arena, - // lifetimes: Arena, + pub lifetimes: Arena, pub where_predicates: Vec, } @@ -53,16 +59,17 @@ pub struct GenericParams { /// It might still result in multiple actual predicates though, because of /// associated type bindings like `Iterator`. #[derive(Clone, PartialEq, Eq, Debug)] -pub struct WherePredicate { - pub target: WherePredicateTarget, - pub bound: TypeBound, +pub enum WherePredicate { + TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, + Lifetime { target: LifetimeRef, bound: LifetimeRef }, } #[derive(Clone, PartialEq, Eq, Debug)] -pub enum WherePredicateTarget { +pub enum WherePredicateTypeTarget { TypeRef(TypeRef), /// For desugared where predicates that can directly refer to a type param. TypeParam(LocalTypeParamId), + // FIXME: ForLifetime(Vec, TypeRef) } type SourceMap = ArenaMap>; @@ -123,7 +130,7 @@ impl GenericParams { } fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile) { - let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; + let mut generics = GenericParams::default(); let mut sm = ArenaMap::default(); // FIXME: add `: Sized` bound for everything except for `Self` in traits @@ -171,7 +178,7 @@ impl GenericParams { // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar let self_param = TypeRef::Path(name![Self].into()); - generics.fill_bounds(&lower_ctx, &src.value, self_param); + generics.fill_bounds(&lower_ctx, &src.value, Either::Left(self_param)); generics.fill(&lower_ctx, &mut sm, &src.value); src.file_id @@ -218,12 +225,12 @@ impl GenericParams { &mut self, lower_ctx: &LowerCtx, node: &dyn ast::TypeBoundsOwner, - type_ref: TypeRef, + target: Either, ) { for bound in node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) { - self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); + self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); } } @@ -246,19 +253,30 @@ impl GenericParams { sm.insert(param_id, Either::Right(type_param.clone())); let type_ref = TypeRef::Path(name.into()); - self.fill_bounds(&lower_ctx, &type_param, type_ref); + self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref)); + } + for lifetime_param in params.lifetime_params() { + let name = lifetime_param + .lifetime_token() + .map_or_else(Name::missing, |tok| Name::new_lifetime(&tok)); + let param = LifetimeParamData { name: name.clone() }; + let _param_id = self.lifetimes.alloc(param); + let lifetime_ref = LifetimeRef::new_name(name); + self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); } } fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { for pred in where_clause.predicates() { - let type_ref = match pred.ty() { - Some(type_ref) => type_ref, - None => continue, + let target = if let Some(type_ref) = pred.ty() { + Either::Left(TypeRef::from_ast(lower_ctx, type_ref)) + } else if let Some(lifetime_tok) = pred.lifetime_token() { + Either::Right(LifetimeRef::from_token(lifetime_tok)) + } else { + continue; }; - let type_ref = TypeRef::from_ast(lower_ctx, type_ref); for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { - self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); + self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); } } } @@ -267,15 +285,24 @@ impl GenericParams { &mut self, lower_ctx: &LowerCtx, bound: ast::TypeBound, - type_ref: TypeRef, + target: Either, ) { if bound.question_mark_token().is_some() { // FIXME: remove this bound return; } let bound = TypeBound::from_ast(lower_ctx, bound); - self.where_predicates - .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); + let predicate = match (target, bound) { + (Either::Left(type_ref), bound) => WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeRef(type_ref), + bound, + }, + (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { + WherePredicate::Lifetime { target: lifetime, bound } + } + _ => return, + }; + self.where_predicates.push(predicate); } pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { @@ -288,8 +315,8 @@ impl GenericParams { }; let param_id = self.types.alloc(param); for bound in bounds { - self.where_predicates.push(WherePredicate { - target: WherePredicateTarget::TypeParam(param_id), + self.where_predicates.push(WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeParam(param_id), bound: bound.clone(), }); } diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index c017b352d86..c6ada271e99 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -255,7 +255,7 @@ impl GenericParamsStorage { } static EMPTY_GENERICS: GenericParams = - GenericParams { types: Arena::new(), where_predicates: Vec::new() }; + GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() }; #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 63b2826f857..f7ce2e26df8 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -13,6 +13,7 @@ use syntax::{ use crate::{ attr::Attrs, generics::{GenericParams, TypeParamData, TypeParamProvenance}, + type_ref::LifetimeRef, }; use super::*; @@ -292,12 +293,16 @@ impl Ctx { let self_type = TypeRef::Path(name![Self].into()); match self_param.kind() { ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => { - TypeRef::Reference(Box::new(self_type), Mutability::Shared) - } - ast::SelfParamKind::MutRef => { - TypeRef::Reference(Box::new(self_type), Mutability::Mut) - } + ast::SelfParamKind::Ref => TypeRef::Reference( + Box::new(self_type), + self_param.lifetime_token().map(LifetimeRef::from_token), + Mutability::Shared, + ), + ast::SelfParamKind::MutRef => TypeRef::Reference( + Box::new(self_type), + self_param.lifetime_token().map(LifetimeRef::from_token), + Mutability::Mut, + ), } } }; @@ -629,8 +634,7 @@ impl Ctx { // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar let self_param = TypeRef::Path(name![Self].into()); - generics.fill_bounds(&self.body_ctx, trait_def, self_param); - + generics.fill_bounds(&self.body_ctx, trait_def, Either::Left(self_param)); generics.fill(&self.body_ctx, &mut sm, node); } GenericsOwner::Impl => { diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index a75d4d302f8..7e2199a9c7f 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs @@ -224,6 +224,13 @@ pub struct TypeParamId { pub type LocalTypeParamId = Idx; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LifetimeParamId { + pub parent: GenericDefId, + pub local_id: LocalLifetimeParamId, +} +pub type LocalLifetimeParamId = Idx; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ContainerId { ModuleId(ModuleId), diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 5b8c1e449ea..00a69a8a63d 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs @@ -7,7 +7,7 @@ use std::{ sync::Arc, }; -use crate::body::LowerCtx; +use crate::{body::LowerCtx, type_ref::LifetimeRef}; use base_db::CrateId; use hir_expand::{ hygiene::Hygiene, @@ -145,7 +145,7 @@ pub struct AssociatedTypeBinding { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum GenericArg { Type(TypeRef), - // or lifetime... + Lifetime(LifetimeRef), } impl Path { diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 07b9723ce01..60fa7646b2c 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs @@ -15,7 +15,7 @@ use super::AssociatedTypeBinding; use crate::{ body::LowerCtx, path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, - type_ref::{TypeBound, TypeRef}, + type_ref::{LifetimeRef, TypeBound, TypeRef}, }; pub(super) use lower_use::lower_use_tree; @@ -170,8 +170,14 @@ pub(super) fn lower_generic_args( bindings.push(AssociatedTypeBinding { name, type_ref, bounds }); } } - // Lifetimes and constants are ignored for now. - ast::GenericArg::LifetimeArg(_) | ast::GenericArg::ConstArg(_) => (), + ast::GenericArg::LifetimeArg(lifetime_arg) => { + if let Some(lifetime) = lifetime_arg.lifetime_token() { + let lifetime_ref = LifetimeRef::from_token(lifetime); + args.push(GenericArg::Lifetime(lifetime_ref)) + } + } + // constants are ignored for now. + ast::GenericArg::ConstArg(_) => (), } } diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index 1a78c1444c4..347ceabb9b0 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs @@ -1,6 +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 syntax::ast::{self}; +use hir_expand::name::Name; +use syntax::{ast, SyntaxToken}; use crate::{body::LowerCtx, path::Path}; @@ -58,7 +59,7 @@ pub enum TypeRef { Tuple(Vec), Path(Path), RawPtr(Box, Mutability), - Reference(Box, Mutability), + Reference(Box, Option, Mutability), Array(Box /*, Expr*/), Slice(Box), /// A fn pointer. Last element of the vector is the return type. @@ -69,11 +70,30 @@ pub enum TypeRef { Error, } +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct LifetimeRef { + pub name: Name, +} + +impl LifetimeRef { + pub(crate) fn new_name(name: Name) -> Self { + LifetimeRef { name } + } + + pub(crate) fn from_token(token: SyntaxToken) -> Self { + LifetimeRef { name: Name::new_lifetime(&token) } + } + + pub fn missing() -> LifetimeRef { + LifetimeRef { name: Name::missing() } + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeBound { Path(Path), - // also for<> bounds - // also Lifetimes + // ForLifetime(Vec, Path), FIXME ForLifetime + Lifetime(LifetimeRef), Error, } @@ -107,8 +127,9 @@ impl TypeRef { } 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 mutability = Mutability::from_mutable(inner.mut_token().is_some()); - TypeRef::Reference(Box::new(inner_ty), mutability) + TypeRef::Reference(Box::new(inner_ty), lifetime, mutability) } ast::Type::InferType(_inner) => TypeRef::Placeholder, ast::Type::FnPtrType(inner) => { @@ -163,14 +184,14 @@ impl TypeRef { types.iter().for_each(|t| go(t, f)) } TypeRef::RawPtr(type_ref, _) - | TypeRef::Reference(type_ref, _) + | TypeRef::Reference(type_ref, ..) | TypeRef::Array(type_ref) | TypeRef::Slice(type_ref) => go(&type_ref, f), TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { for bound in bounds { match bound { TypeBound::Path(path) => go_path(path, f), - TypeBound::Error => (), + TypeBound::Lifetime(_) | TypeBound::Error => (), } } } @@ -186,8 +207,12 @@ impl TypeRef { for segment in path.segments().iter() { if let Some(args_and_bindings) = segment.args_and_bindings { for arg in &args_and_bindings.args { - let crate::path::GenericArg::Type(type_ref) = arg; - go(type_ref, f); + match arg { + crate::path::GenericArg::Type(type_ref) => { + go(type_ref, f); + } + crate::path::GenericArg::Lifetime(_) => {} + } } for binding in &args_and_bindings.bindings { if let Some(type_ref) = &binding.type_ref { @@ -196,7 +221,7 @@ impl TypeRef { for bound in &binding.bounds { match bound { TypeBound::Path(path) => go_path(path, f), - TypeBound::Error => (), + TypeBound::Lifetime(_) | TypeBound::Error => (), } } } @@ -232,7 +257,10 @@ impl TypeBound { }; TypeBound::Path(path) } - ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error, + ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType + ast::TypeBoundKind::Lifetime(lifetime) => { + TypeBound::Lifetime(LifetimeRef::from_token(lifetime)) + } } } diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index b26ffa1ef2e..583ed6142bc 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs @@ -38,7 +38,7 @@ impl Name { } pub fn new_lifetime(lt: &syntax::SyntaxToken) -> Name { - assert!(lt.kind() == syntax::SyntaxKind::LIFETIME); + assert_eq!(lt.kind(), syntax::SyntaxKind::LIFETIME); Name(Repr::Text(lt.text().clone())) } @@ -250,6 +250,8 @@ pub mod known { pub const SELF_PARAM: super::Name = super::Name::new_inline("self"); pub const SELF_TYPE: super::Name = super::Name::new_inline("Self"); + pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static"); + #[macro_export] macro_rules! name { (self) => { @@ -258,6 +260,9 @@ pub mod known { (Self) => { $crate::name::known::SELF_TYPE }; + ('static) => { + $crate::name::known::STATIC_LIFETIME + }; ($ident:ident) => { $crate::name::known::$ident }; diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index e774819060d..0d968cc6865 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -4,7 +4,7 @@ use std::fmt; use crate::{ db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, - Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, + Lifetime, Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, }; use hir_def::{ find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, @@ -710,6 +710,19 @@ impl HirDisplay for GenericPredicate { } } +impl HirDisplay for Lifetime { + fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { + match self { + Lifetime::Parameter(id) => { + let generics = generics(f.db.upcast(), id.parent); + let param_data = &generics.params.lifetimes[id.local_id]; + write!(f, "{}", ¶m_data.name) + } + Lifetime::Static => write!(f, "'static"), + } + } +} + impl HirDisplay for Obligation { fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { match self { diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index d7ad198b34b..ca005bc99d6 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -862,6 +862,7 @@ impl<'a> InferenceContext<'a> { let ty = self.make_ty(type_ref); substs.push(ty); } + GenericArg::Lifetime(_) => {} } } }; diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 5a8c971985d..357bd92f997 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs @@ -29,8 +29,8 @@ use base_db::{salsa, CrateId}; use hir_def::{ expr::ExprId, type_ref::{Mutability, Rawness}, - AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, - TypeParamId, + AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, LifetimeParamId, Lookup, + TraitId, TypeAliasId, TypeParamId, }; use itertools::Itertools; @@ -52,6 +52,12 @@ pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironmen pub use chalk_ir::{BoundVar, DebruijnIndex}; +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum Lifetime { + Parameter(LifetimeParamId), + Static, +} + /// A type constructor or type name: this might be something like the primitive /// type `bool`, a struct like `Vec`, or things like function pointers or /// tuples. diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 708e2af0fa9..92f779360f7 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -12,7 +12,7 @@ use base_db::CrateId; use hir_def::{ adt::StructKind, builtin_type::BuiltinType, - generics::{TypeParamProvenance, WherePredicate, WherePredicateTarget}, + generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, @@ -171,7 +171,7 @@ impl Ty { let inner_ty = Ty::from_hir(ctx, inner); Ty::apply_one(TypeCtor::Slice, inner_ty) } - TypeRef::Reference(inner, mutability) => { + TypeRef::Reference(inner, _, mutability) => { let inner_ty = Ty::from_hir(ctx, inner); Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) } @@ -555,7 +555,7 @@ fn substs_from_path_segment( substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); - let mut had_explicit_args = false; + let mut had_explicit_type_args = false; if let Some(generic_args) = &segment.args_and_bindings { if !generic_args.has_self_type { @@ -568,10 +568,11 @@ fn substs_from_path_segment( for arg in generic_args.args.iter().skip(skip).take(expected_num) { match arg { GenericArg::Type(type_ref) => { - had_explicit_args = true; + had_explicit_type_args = true; let ty = Ty::from_hir(ctx, type_ref); substs.push(ty); } + GenericArg::Lifetime(_) => {} } } } @@ -579,7 +580,7 @@ fn substs_from_path_segment( // handle defaults. In expression or pattern path segments without // explicitly specified type arguments, missing type arguments are inferred // (i.e. defaults aren't used). - if !infer_args || had_explicit_args { + if !infer_args || had_explicit_type_args { if let Some(def_generic) = def_generic { let defaults = ctx.db.generic_defaults(def_generic); assert_eq!(total_len, defaults.len()); @@ -657,7 +658,7 @@ impl TraitRef { ) -> Option { match bound { TypeBound::Path(path) => TraitRef::from_path(ctx, path, Some(self_ty)), - TypeBound::Error => None, + TypeBound::Lifetime(_) | TypeBound::Error => None, } } } @@ -667,22 +668,30 @@ impl GenericPredicate { ctx: &'a TyLoweringContext<'a>, where_predicate: &'a WherePredicate, ) -> impl Iterator + 'a { - let self_ty = match &where_predicate.target { - WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), - WherePredicateTarget::TypeParam(param_id) => { - let generic_def = ctx.resolver.generic_def().expect("generics in scope"); - let generics = generics(ctx.db.upcast(), generic_def); - let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; - match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), - TypeParamLoweringMode::Variable => { - let idx = generics.param_idx(param_id).expect("matching generics"); - Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)) + match where_predicate { + WherePredicate::TypeBound { target, bound } => { + let self_ty = match target { + WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), + WherePredicateTypeTarget::TypeParam(param_id) => { + let generic_def = ctx.resolver.generic_def().expect("generics in scope"); + let generics = generics(ctx.db.upcast(), generic_def); + let param_id = + hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; + match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), + TypeParamLoweringMode::Variable => { + let idx = generics.param_idx(param_id).expect("matching generics"); + Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)) + } + } } - } + }; + GenericPredicate::from_type_bound(ctx, bound, self_ty) + .collect::>() + .into_iter() } - }; - GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) + WherePredicate::Lifetime { .. } => vec![].into_iter(), + } } pub(crate) fn from_type_bound<'a>( @@ -707,7 +716,7 @@ fn assoc_type_bindings_from_type_bound<'a>( ) -> impl Iterator + 'a { let last_segment = match bound { TypeBound::Path(path) => path.segments().last(), - TypeBound::Error => None, + TypeBound::Error | TypeBound::Lifetime(_) => None, }; last_segment .into_iter() @@ -872,11 +881,16 @@ pub(crate) fn generic_predicates_for_param_query( resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them - .filter(|pred| match &pred.target { - WherePredicateTarget::TypeRef(type_ref) => { - Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) - } - WherePredicateTarget::TypeParam(local_id) => *local_id == param_id.local_id, + .filter(|pred| match pred { + WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeRef(type_ref), + .. + } => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id), + WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeParam(local_id), + .. + } => *local_id == param_id.local_id, + WherePredicate::Lifetime { .. } => false, }) .flat_map(|pred| { GenericPredicate::from_where_predicate(&ctx, pred) diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs index e3e2442680e..af880c0658c 100644 --- a/crates/hir_ty/src/utils.rs +++ b/crates/hir_ty/src/utils.rs @@ -2,11 +2,10 @@ //! query, but can't be computed directly from `*Data` (ie, which need a `db`). use std::sync::Arc; -use hir_def::generics::WherePredicateTarget; use hir_def::{ adt::VariantData, db::DefDatabase, - generics::{GenericParams, TypeParamData, TypeParamProvenance}, + generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget}, path::Path, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, @@ -27,14 +26,19 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec { generic_params .where_predicates .iter() - .filter_map(|pred| match &pred.target { - WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => { - pred.bound.as_path() - } - WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => { - pred.bound.as_path() - } - _ => None, + .filter_map(|pred| match pred { + hir_def::generics::WherePredicate::TypeBound { target, bound } => match target { + WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) + if p == &Path::from(name![Self]) => + { + bound.as_path() + } + WherePredicateTypeTarget::TypeParam(local_id) if Some(*local_id) == trait_self => { + bound.as_path() + } + _ => None, + }, + hir_def::generics::WherePredicate::Lifetime { .. } => None, }) .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { Some(TypeNs::TraitId(t)) => Some(t),