From d21cdf3c998bb24e48e81a7e6909df2146ce097c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 15:13:05 +0200 Subject: Lower `Fn(X, Y) -> Z` paths --- crates/ra_hir/src/path.rs | 44 +++++++++++++++++++++++++++++++---- crates/ra_hir/src/ty/tests.rs | 16 ++++++------- crates/ra_syntax/src/ast/generated.rs | 6 +++++ crates/ra_syntax/src/grammar.ron | 2 +- 4 files changed, 55 insertions(+), 13 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 24316fc91..d6c78593b 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -1,11 +1,11 @@ use std::sync::Arc; use ra_syntax::{ - ast::{self, NameOwner}, + ast::{self, NameOwner, TypeAscriptionOwner}, AstNode, }; -use crate::{type_ref::TypeRef, AsName, Name}; +use crate::{name, type_ref::TypeRef, AsName, Name}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { @@ -76,8 +76,16 @@ impl Path { match segment.kind()? { ast::PathSegmentKind::Name(name) => { - let args = - segment.type_arg_list().and_then(GenericArgs::from_ast).map(Arc::new); + let args = segment + .type_arg_list() + .and_then(GenericArgs::from_ast) + .or_else(|| { + GenericArgs::from_fn_like_path_ast( + segment.param_list(), + segment.ret_type(), + ) + }) + .map(Arc::new); let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; segments.push(segment); } @@ -187,6 +195,34 @@ impl GenericArgs { } } + /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) + /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). + pub(crate) fn from_fn_like_path_ast( + params: Option, + ret_type: Option, + ) -> Option { + let mut args = Vec::new(); + let mut bindings = Vec::new(); + if let Some(params) = params { + let mut param_types = Vec::new(); + for param in params.params() { + let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); + param_types.push(type_ref); + } + let arg = GenericArg::Type(TypeRef::Tuple(param_types)); + args.push(arg); + } + if let Some(ret_type) = ret_type { + let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); + bindings.push((name::OUTPUT, type_ref)) + } + if args.is_empty() && bindings.is_empty() { + None + } else { + Some(GenericArgs { args, has_self_type: false, bindings }) + } + } + pub(crate) fn empty() -> GenericArgs { GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 17c4e3556..c414e6a95 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3736,7 +3736,7 @@ fn fn_trait() { trait FnOnce { type Output; - fn call_once(self, args: Args) -> Self::Output; + fn call_once(self, args: Args) -> >::Output; } fn test u128>(f: F) { @@ -3746,13 +3746,13 @@ fn test u128>(f: F) { @r###" [57; 61) 'self': Self [63; 67) 'args': Args - [132; 133) 'f': F - [138; 166) '{ ...2)); }': () - [144; 145) 'f': F - [144; 163) 'f.call...1, 2))': {unknown} - [156; 162) '(1, 2)': (i32, i32) - [157; 158) '1': i32 - [160; 161) '2': i32 + [150; 151) 'f': F + [156; 184) '{ ...2)); }': () + [162; 163) 'f': F + [162; 181) 'f.call...1, 2))': {unknown} + [174; 180) '(1, 2)': (u32, u64) + [175; 176) '1': u32 + [178; 179) '2': u64 "### ); } diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index bcf753f78..d274b6fbc 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -2312,6 +2312,12 @@ impl PathSegment { pub fn type_arg_list(&self) -> Option { AstChildren::new(&self.syntax).next() } + pub fn param_list(&self) -> Option { + AstChildren::new(&self.syntax).next() + } + pub fn ret_type(&self) -> Option { + AstChildren::new(&self.syntax).next() + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PathType { diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 3e6c2d3f3..993e58e64 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -684,7 +684,7 @@ Grammar( ] ), "PathSegment": ( - options: [ "NameRef", "TypeArgList" ] + options: [ "NameRef", "TypeArgList", "ParamList", "RetType" ] ), "TypeArgList": (collections: [ ("type_args", "TypeArg"), -- cgit v1.2.3