From db32a2e4211f9444ef4f10b633e400d27ed2662e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 10 Apr 2020 22:05:46 +0200 Subject: Implement inline associated type bounds Like `Iterator`. This is an unstable feature, but it's used in the standard library e.g. in the definition of Flatten, so we can't get away with not implementing it :) --- crates/ra_hir_def/src/data.rs | 8 ++++++-- crates/ra_hir_def/src/path.rs | 21 +++++++++++++++++++-- crates/ra_hir_def/src/path/lower.rs | 21 ++++++++++++++++----- crates/ra_hir_def/src/type_ref.rs | 12 ++++++++++-- 4 files changed, 51 insertions(+), 11 deletions(-) (limited to 'crates/ra_hir_def') diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 56a20c5bd..b3c91fea2 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -15,7 +15,7 @@ use ra_syntax::ast::{ use crate::{ attr::Attrs, db::DefDatabase, - path::{path, GenericArgs, Path}, + path::{path, AssociatedTypeBinding, GenericArgs, Path}, src::HasSource, type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, @@ -95,7 +95,11 @@ fn desugar_future_path(orig: TypeRef) -> Path { let path = path![std::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); let mut last = GenericArgs::empty(); - last.bindings.push((name![Output], orig)); + last.bindings.push(AssociatedTypeBinding { + name: name![Output], + type_ref: Some(orig), + bounds: Vec::new(), + }); generic_args.push(Some(Arc::new(last))); Path::from_known_path(path, generic_args) diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 91c7b3e09..162b3c8c7 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -14,7 +14,10 @@ use hir_expand::{ use ra_db::CrateId; use ra_syntax::ast; -use crate::{type_ref::TypeRef, InFile}; +use crate::{ + type_ref::{TypeBound, TypeRef}, + InFile, +}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ModPath { @@ -111,7 +114,21 @@ pub struct GenericArgs { /// is left out. pub has_self_type: bool, /// Associated type bindings like in `Iterator`. - pub bindings: Vec<(Name, TypeRef)>, + pub bindings: Vec, +} + +/// An associated type binding like in `Iterator`. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AssociatedTypeBinding { + /// The name of the associated type. + pub name: Name, + /// The type bound to this associated type (in `Item = T`, this would be the + /// `T`). This can be `None` if there are bounds instead. + pub type_ref: Option, + /// Bounds for the associated type, like in `Iterator`. (This is the unstable `associated_type_bounds` + /// feature.) + pub bounds: Vec, } /// A single generic argument. diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 0f806d6fb..9ec2e0dcd 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -9,11 +9,12 @@ use hir_expand::{ hygiene::Hygiene, name::{name, AsName}, }; -use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner}; +use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; +use super::AssociatedTypeBinding; use crate::{ path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, - type_ref::TypeRef, + type_ref::{TypeBound, TypeRef}, }; pub(super) use lower_use::lower_use_tree; @@ -136,10 +137,16 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option // lifetimes ignored for now let mut bindings = Vec::new(); for assoc_type_arg in node.assoc_type_args() { + let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg; if let Some(name_ref) = assoc_type_arg.name_ref() { let name = name_ref.as_name(); - let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); - bindings.push((name, type_ref)); + let type_ref = assoc_type_arg.type_ref().map(TypeRef::from_ast); + let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { + l.bounds().map(TypeBound::from_ast).collect() + } else { + Vec::new() + }; + bindings.push(AssociatedTypeBinding { name, type_ref, bounds }); } } if args.is_empty() && bindings.is_empty() { @@ -168,7 +175,11 @@ fn lower_generic_args_from_fn_path( } if let Some(ret_type) = ret_type { let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); - bindings.push((name![Output], type_ref)) + bindings.push(AssociatedTypeBinding { + name: name![Output], + type_ref: Some(type_ref), + bounds: Vec::new(), + }); } if args.is_empty() && bindings.is_empty() { None diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index ea29c4176..f308c6bdf 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -163,8 +163,16 @@ impl TypeRef { let crate::path::GenericArg::Type(type_ref) = arg; go(type_ref, f); } - for (_, type_ref) in &args_and_bindings.bindings { - go(type_ref, f); + for binding in &args_and_bindings.bindings { + if let Some(type_ref) = &binding.type_ref { + go(type_ref, f); + } + for bound in &binding.bounds { + match bound { + TypeBound::Path(path) => go_path(path, f), + TypeBound::Error => (), + } + } } } } -- cgit v1.2.3 From c8b2ec8c20be44ae19d15e90ff812745f029899e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 12 Apr 2020 12:28:24 +0200 Subject: Add support for bounds on associated types in trait definitions E.g. ``` trait Trait { type Item: SomeOtherTrait; } ``` Note that these don't simply desugar to where clauses; as I understand it, where clauses have to be proved by the *user* of the trait, but these bounds are proved by the *implementor*. (Also, where clauses on associated types are unstable.) --- crates/ra_hir_def/src/data.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_def') diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 56a20c5bd..5dfde75d9 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -9,7 +9,8 @@ use hir_expand::{ }; use ra_prof::profile; use ra_syntax::ast::{ - self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner, + self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, + VisibilityOwner, }; use crate::{ @@ -106,6 +107,7 @@ pub struct TypeAliasData { pub name: Name, pub type_ref: Option, pub visibility: RawVisibility, + pub bounds: Vec, } impl TypeAliasData { @@ -118,9 +120,17 @@ impl TypeAliasData { let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); let type_ref = node.value.type_ref().map(TypeRef::from_ast); let vis_default = RawVisibility::default_for_container(loc.container); - let visibility = - RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); - Arc::new(TypeAliasData { name, type_ref, visibility }) + let visibility = RawVisibility::from_ast_with_default( + db, + vis_default, + node.as_ref().map(|n| n.visibility()), + ); + let bounds = if let Some(bound_list) = node.value.type_bound_list() { + bound_list.bounds().map(TypeBound::from_ast).collect() + } else { + Vec::new() + }; + Arc::new(TypeAliasData { name, type_ref, visibility, bounds }) } } -- cgit v1.2.3 From eedab116ab9cf49860902fa051bb492653dab50c Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 14 Apr 2020 13:57:02 -0400 Subject: insta 0.16 --- crates/ra_hir_def/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_def') diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 56e791e3e..b85358308 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -28,4 +28,4 @@ ra_cfg = { path = "../ra_cfg" } tt = { path = "../ra_tt", package = "ra_tt" } [dev-dependencies] -insta = "0.15.0" +insta = "0.16.0" -- cgit v1.2.3