about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2020-12-17 22:01:42 +0100
committerLukas Wirth <lukastw97@gmail.com>2020-12-17 22:01:42 +0100
commitfa65d6ba855fb2da68840b987bfdec258239a59b (patch)
tree64700d82eec8ab83912aa7d8eb752fe6becc7b7c
parentc8c58d81eca78b322675afa053463e06c422cfbc (diff)
downloadrust-fa65d6ba855fb2da68840b987bfdec258239a59b.tar.gz
rust-fa65d6ba855fb2da68840b987bfdec258239a59b.zip
Higher-ranked trait bounds for where clauses
-rw-r--r--crates/hir_def/src/generics.rs37
-rw-r--r--crates/hir_ty/src/lower.rs18
-rw-r--r--crates/hir_ty/src/utils.rs9
-rw-r--r--crates/ide/src/goto_definition.rs28
4 files changed, 74 insertions, 18 deletions
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 41134d23b3d..bb8fca009a1 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -62,6 +62,7 @@ pub struct GenericParams {
 pub enum WherePredicate {
     TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
     Lifetime { target: LifetimeRef, bound: LifetimeRef },
+    ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
@@ -69,7 +70,6 @@ pub enum WherePredicateTypeTarget {
     TypeRef(TypeRef),
     /// For desugared where predicates that can directly refer to a type param.
     TypeParam(LocalTypeParamId),
-    // FIXME: ForLifetime(Vec<LifetimeParamId>, TypeRef)
 }
 
 #[derive(Default)]
@@ -234,7 +234,7 @@ impl GenericParams {
         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, target.clone());
+            self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
         }
     }
 
@@ -279,8 +279,25 @@ impl GenericParams {
             } else {
                 continue;
             };
+
+            let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
+                // Higher-Ranked Trait Bounds
+                param_list
+                    .lifetime_params()
+                    .map(|lifetime_param| {
+                        lifetime_param
+                            .lifetime()
+                            .map_or_else(Name::missing, |lt| Name::new_lifetime(&lt))
+                    })
+                    .collect()
+            });
             for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
-                self.add_where_predicate_from_bound(lower_ctx, bound, target.clone());
+                self.add_where_predicate_from_bound(
+                    lower_ctx,
+                    bound,
+                    lifetimes.as_ref(),
+                    target.clone(),
+                );
             }
         }
     }
@@ -289,6 +306,7 @@ impl GenericParams {
         &mut self,
         lower_ctx: &LowerCtx,
         bound: ast::TypeBound,
+        hrtb_lifetimes: Option<&Box<[Name]>>,
         target: Either<TypeRef, LifetimeRef>,
     ) {
         if bound.question_mark_token().is_some() {
@@ -297,9 +315,16 @@ impl GenericParams {
         }
         let bound = TypeBound::from_ast(lower_ctx, bound);
         let predicate = match (target, bound) {
-            (Either::Left(type_ref), bound) => WherePredicate::TypeBound {
-                target: WherePredicateTypeTarget::TypeRef(type_ref),
-                bound,
+            (Either::Left(type_ref), bound) => match hrtb_lifetimes {
+                Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
+                    lifetimes: hrtb_lifetimes.clone(),
+                    target: WherePredicateTypeTarget::TypeRef(type_ref),
+                    bound,
+                },
+                None => WherePredicate::TypeBound {
+                    target: WherePredicateTypeTarget::TypeRef(type_ref),
+                    bound,
+                },
             },
             (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
                 WherePredicate::Lifetime { target: lifetime, bound }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 8392cb77065..8da56cd11c8 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -675,7 +675,8 @@ impl GenericPredicate {
         where_predicate: &'a WherePredicate,
     ) -> impl Iterator<Item = GenericPredicate> + 'a {
         match where_predicate {
-            WherePredicate::TypeBound { target, bound } => {
+            WherePredicate::ForLifetime { target, bound, .. }
+            | WherePredicate::TypeBound { target, bound } => {
                 let self_ty = match target {
                     WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
                     WherePredicateTypeTarget::TypeParam(param_id) => {
@@ -888,14 +889,13 @@ pub(crate) fn generic_predicates_for_param_query(
         .where_predicates_in_scope()
         // we have to filter out all other predicates *first*, before attempting to lower them
         .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::ForLifetime { target, .. }
+            | WherePredicate::TypeBound { target, .. } => match target {
+                WherePredicateTypeTarget::TypeRef(type_ref) => {
+                    Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id)
+                }
+                WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id,
+            },
             WherePredicate::Lifetime { .. } => false,
         })
         .flat_map(|pred| {
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index af880c0658c..65b79df0d51 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -5,7 +5,9 @@ use std::sync::Arc;
 use hir_def::{
     adt::VariantData,
     db::DefDatabase,
-    generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget},
+    generics::{
+        GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+    },
     path::Path,
     resolver::{HasResolver, TypeNs},
     type_ref::TypeRef,
@@ -27,7 +29,8 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
         .where_predicates
         .iter()
         .filter_map(|pred| match pred {
-            hir_def::generics::WherePredicate::TypeBound { target, bound } => match target {
+            WherePredicate::ForLifetime { target, bound, .. }
+            | WherePredicate::TypeBound { target, bound } => match target {
                 WherePredicateTypeTarget::TypeRef(TypeRef::Path(p))
                     if p == &Path::from(name![Self]) =>
                 {
@@ -38,7 +41,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
                 }
                 _ => None,
             },
-            hir_def::generics::WherePredicate::Lifetime { .. } => None,
+            WherePredicate::Lifetime { .. } => None,
         })
         .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
             Some(TypeNs::TraitId(t)) => Some(t),
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 173509b08bd..d75ae447bb0 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1077,4 +1077,32 @@ fn foo<'foobar>(_: &'foobar ()) {
 }"#,
         )
     }
+
+    #[test]
+    #[ignore] // requires the HIR to somehow track these hrtb lifetimes
+    fn goto_lifetime_hrtb() {
+        check(
+            r#"trait Foo<T> {}
+fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {}
+                    //^^
+"#,
+        );
+        check(
+            r#"trait Foo<T> {}
+fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {}
+                    //^^
+"#,
+        );
+    }
+
+    #[test]
+    #[ignore] // requires ForTypes to be implemented
+    fn goto_lifetime_hrtb_for_type() {
+        check(
+            r#"trait Foo<T> {}
+fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {}
+                       //^^
+"#,
+        );
+    }
 }