843: Impl generics r=matklad a=flodiebold

This handles type parameters on impls when typing method calls.

~One remaining problem is that the autoderefs aren't applied during the unification of the method receiver type with the actual receiver type, which means that the type parameters are only correctly inferred if no autoderefs happened.~

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2019-02-17 13:56:22 +00:00
commit f937d11ad8
16 changed files with 290 additions and 84 deletions

View File

@ -463,7 +463,7 @@ impl Function {
self.id.source(db)
}
pub fn module(&self, db: &impl HirDatabase) -> Module {
pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db)
}
@ -497,6 +497,12 @@ impl Function {
db.generic_params((*self).into())
}
/// The containing impl block, if this is a method.
pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
// TODO: move to a more general type for 'body-having' items
/// Builds a resolver for code inside this item.
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
@ -527,6 +533,16 @@ impl Const {
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ConstDef>) {
self.id.source(db)
}
pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db)
}
/// The containing impl block, if this is a method.
pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
}
impl Docs for Const {
@ -544,6 +560,10 @@ impl Static {
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::StaticDef>) {
self.id.source(db)
}
pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db)
}
}
impl Docs for Static {
@ -562,6 +582,10 @@ impl Trait {
self.id.source(db)
}
pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db)
}
pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into())
}
@ -586,6 +610,16 @@ impl Type {
pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into())
}
pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db)
}
/// The containing impl block, if this is a method.
pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
}
impl Docs for Type {

View File

@ -3,22 +3,11 @@ use std::sync::Arc;
use ra_syntax::ast::{self, NameOwner};
use crate::{
HirDatabase, Name, AsName, Function, FnSignature,
Name, AsName, Function, FnSignature,
type_ref::{TypeRef, Mutability},
PersistentHirDatabase,
impl_block::ImplBlock,
};
impl Function {
// TODO impl_block should probably also be part of the code model API?
/// The containing impl block, if this is a method.
pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
}
impl FnSignature {
pub(crate) fn fn_signature_query(
db: &impl PersistentHirDatabase,

View File

@ -14,7 +14,7 @@ use crate::{
name::AsName,
type_ref::{Mutability, TypeRef},
};
use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy};
use crate::{ path::GenericArgs, ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}};
pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
@ -193,6 +193,7 @@ pub enum Expr {
receiver: ExprId,
method_name: Name,
args: Vec<ExprId>,
generic_args: Option<GenericArgs>,
},
Match {
expr: ExprId,
@ -597,7 +598,11 @@ impl ExprCollector {
Vec::new()
};
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
self.alloc_expr(Expr::MethodCall { receiver, method_name, args }, syntax_ptr)
let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
self.alloc_expr(
Expr::MethodCall { receiver, method_name, args, generic_args },
syntax_ptr,
)
}
ast::ExprKind::MatchExpr(e) => {
let expr = self.collect_expr_opt(e.expr());

View File

@ -7,7 +7,7 @@ use std::sync::Arc;
use ra_syntax::ast::{self, NameOwner, TypeParamsOwner};
use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Trait, Type};
use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Trait, Type, ImplBlock};
/// Data about a generic parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)]
@ -20,6 +20,7 @@ pub struct GenericParam {
/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct GenericParams {
pub(crate) parent_params: Option<Arc<GenericParams>>,
pub(crate) params: Vec<GenericParam>,
}
@ -30,8 +31,9 @@ pub enum GenericDef {
Enum(Enum),
Trait(Trait),
Type(Type),
ImplBlock(ImplBlock),
}
impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type);
impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type, ImplBlock);
impl GenericParams {
pub(crate) fn generic_params_query(
@ -39,27 +41,36 @@ impl GenericParams {
def: GenericDef,
) -> Arc<GenericParams> {
let mut generics = GenericParams::default();
let parent = match def {
GenericDef::Function(it) => it.impl_block(db),
GenericDef::Type(it) => it.impl_block(db),
GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None,
GenericDef::ImplBlock(_) => None,
};
generics.parent_params = parent.map(|p| p.generic_params(db));
let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
match def {
GenericDef::Function(it) => generics.fill(&*it.source(db).1),
GenericDef::Struct(it) => generics.fill(&*it.source(db).1),
GenericDef::Enum(it) => generics.fill(&*it.source(db).1),
GenericDef::Trait(it) => generics.fill(&*it.source(db).1),
GenericDef::Type(it) => generics.fill(&*it.source(db).1),
GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Type(it) => generics.fill(&*it.source(db).1, start),
GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
}
Arc::new(generics)
}
fn fill(&mut self, node: &impl TypeParamsOwner) {
fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
if let Some(params) = node.type_param_list() {
self.fill_params(params)
self.fill_params(params, start)
}
}
fn fill_params(&mut self, params: &ast::TypeParamList) {
fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
for (idx, type_param) in params.type_params().enumerate() {
let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
let param = GenericParam { idx: idx as u32, name };
let param = GenericParam { idx: idx as u32 + start, name };
self.params.push(param);
}
}
@ -67,4 +78,13 @@ impl GenericParams {
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
self.params.iter().find(|p| &p.name == name)
}
pub fn count_parent_params(&self) -> usize {
self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
}
pub fn count_params_including_parent(&self) -> usize {
let parent_count = self.count_parent_params();
parent_count + self.params.len()
}
}

View File

@ -9,7 +9,6 @@ use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast};
use ra_arena::{Arena, RawId, ArenaId, impl_arena_id};
use crate::{
HirDatabase,
Module,
PersistentHirDatabase,
};
@ -215,7 +214,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
(loc.raw.file_id, ast)
}
fn module(self, db: &impl HirDatabase) -> Module {
fn module(self, db: &impl PersistentHirDatabase) -> Module {
let int = Self::interner(db.as_ref());
let loc = int.id2loc(self);
loc.module

View File

@ -13,7 +13,7 @@ use crate::{
type_ref::TypeRef,
ids::LocationCtx,
resolve::Resolver,
ty::Ty,
ty::Ty, generics::GenericParams
};
use crate::code_model_api::{Module, ModuleSource};
@ -38,7 +38,7 @@ impl ImplSourceMap {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImplBlock {
module: Module,
impl_id: ImplId,
@ -58,7 +58,7 @@ impl ImplBlock {
}
/// Returns the syntax of the impl block
pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::ImplBlock>) {
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ImplBlock>) {
let source_map = db.impls_in_module_source_map(self.module);
let (file_id, source) = self.module.definition_source(db);
(file_id, source_map.get(&source, self.impl_id))
@ -72,11 +72,11 @@ impl ImplBlock {
self.module
}
pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TypeRef> {
pub fn target_trait_ref(&self, db: &impl PersistentHirDatabase) -> Option<TypeRef> {
db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned()
}
pub fn target_type(&self, db: &impl HirDatabase) -> TypeRef {
pub fn target_type(&self, db: &impl PersistentHirDatabase) -> TypeRef {
db.impls_in_module(self.module).impls[self.impl_id].target_type().clone()
}
@ -96,13 +96,19 @@ impl ImplBlock {
None
}
pub fn items(&self, db: &impl HirDatabase) -> Vec<ImplItem> {
pub fn items(&self, db: &impl PersistentHirDatabase) -> Vec<ImplItem> {
db.impls_in_module(self.module).impls[self.impl_id].items().to_vec()
}
pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into())
}
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
let r = self.module().resolver(db);
// TODO: add generics
// add generic params, if present
let p = self.generic_params(db);
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
let r = r.push_impl_block_scope(self.clone());
r
}

View File

@ -129,7 +129,7 @@ impl Path {
}
impl GenericArgs {
fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> {
pub(crate) fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> {
let mut args = Vec::new();
for type_arg in node.type_args() {
let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());

View File

@ -165,6 +165,17 @@ impl Substs {
pub fn empty() -> Substs {
Substs(Arc::new([]))
}
/// Replaces the end of the substitutions by other ones.
pub(crate) fn replace_tail(self, replace_by: Vec<Ty>) -> Substs {
// again missing Arc::make_mut_slice...
let len = replace_by.len().min(self.0.len());
let parent_len = self.0.len() - len;
let mut result = Vec::with_capacity(parent_len + len);
result.extend(self.0.iter().take(parent_len).cloned());
result.extend(replace_by);
Substs(result.into())
}
}
/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
@ -421,7 +432,8 @@ impl Ty {
(var.parent_enum(db).generic_params(db), segment)
}
};
// substs_from_path
let parent_param_count = def_generics.count_parent_params();
substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
if let Some(generic_args) = &segment.args_and_bindings {
// if args are provided, it should be all of them, but we can't rely on that
let param_count = def_generics.params.len();
@ -436,9 +448,8 @@ impl Ty {
}
// add placeholders for args that were not provided
// TODO: handle defaults
let supplied_params =
segment.args_and_bindings.as_ref().map(|ga| ga.args.len()).unwrap_or(0);
for _ in supplied_params..def_generics.params.len() {
let supplied_params = substs.len();
for _ in supplied_params..def_generics.count_params_including_parent() {
substs.push(Ty::Unknown);
}
assert_eq!(substs.len(), def_generics.params.len());
@ -666,7 +677,12 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
}
fn make_substs(generics: &GenericParams) -> Substs {
Substs(generics.params.iter().map(|_p| Ty::Unknown).collect::<Vec<_>>().into())
Substs(
(0..generics.count_params_including_parent())
.map(|_p| Ty::Unknown)
.collect::<Vec<_>>()
.into(),
)
}
fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
@ -1362,15 +1378,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
ret_ty
}
Expr::MethodCall { receiver, args, method_name } => {
Expr::MethodCall { receiver, args, method_name, generic_args } => {
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
let method_ty = match resolved {
Some(func) => {
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
Some((ty, func)) => {
self.write_method_resolution(tgt_expr, func);
self.db.type_for_def(func.into())
(ty, self.db.type_for_def(func.into()), Some(func.generic_params(self.db)))
}
None => Ty::Unknown,
None => (Ty::Unknown, receiver_ty, None),
};
// handle provided type arguments
let method_ty = if let Some(generic_args) = generic_args {
// if args are provided, it should be all of them, but we can't rely on that
let param_count = def_generics.map(|g| g.params.len()).unwrap_or(0);
let mut new_substs = Vec::with_capacity(generic_args.args.len());
for arg in generic_args.args.iter().take(param_count) {
match arg {
GenericArg::Type(type_ref) => {
let ty = self.make_ty(type_ref);
new_substs.push(ty);
}
}
}
let substs = method_ty.substs().unwrap_or_else(Substs::empty);
let substs = substs.replace_tail(new_substs);
method_ty.apply_substs(substs)
} else {
method_ty
};
let method_ty = self.insert_type_vars(method_ty);
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
@ -1394,9 +1429,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
};
// TODO we would have to apply the autoderef/autoref steps here
// to get the correct receiver type to unify...
self.unify(&expected_receiver_ty, &receiver_ty);
// Apply autoref so the below unification works correctly
let actual_receiver_ty = match expected_receiver_ty {
Ty::Ref(_, mutability) => Ty::Ref(Arc::new(derefed_receiver_ty), mutability),
_ => derefed_receiver_ty,
};
self.unify(&expected_receiver_ty, &actual_receiver_ty);
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
for (arg, param) in args.iter().zip(param_iter) {
self.infer_expr(*arg, &Expectation::has_type(param));

View File

@ -118,11 +118,13 @@ impl Ty {
// TODO: cache this as a query?
// - if so, what signature? (TyFingerprint, Name)?
// - or maybe cache all names and def_ids of methods per fingerprint?
pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> {
self.iterate_methods(db, |f| {
/// Look up the method with the given name, returning the actual autoderefed
/// receiver type (but without autoref applied yet).
pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> {
self.iterate_methods(db, |ty, f| {
let sig = f.signature(db);
if sig.name() == name && sig.has_self_param() {
Some(f)
Some((ty.clone(), f))
} else {
None
}
@ -134,7 +136,7 @@ impl Ty {
pub fn iterate_methods<T>(
self,
db: &impl HirDatabase,
mut callback: impl FnMut(Function) -> Option<T>,
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
// For method calls, rust first does any number of autoderef, and then one
// autoref (i.e. when the method takes &self or &mut self). We just ignore
@ -156,7 +158,7 @@ impl Ty {
for item in impl_block.items(db) {
match item {
ImplItem::Method(f) => {
if let Some(result) = callback(f) {
if let Some(result) = callback(&derefed_ty, f) {
return Some(result);
}
}

View File

@ -1,36 +1,36 @@
---
created: "2019-01-27T14:52:29.938713255+00:00"
creator: insta@0.5.2
expression: "&result"
created: "2019-02-16T20:53:59.655361804Z"
creator: insta@0.6.2
source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
---
[53; 57) 'self': A<[unknown]>
[65; 87) '{ ... }': [unknown]
[75; 79) 'self': A<[unknown]>
[75; 81) 'self.x': [unknown]
[53; 57) 'self': A<T2>
[65; 87) '{ ... }': T2
[75; 79) 'self': A<T2>
[75; 81) 'self.x': T2
[99; 100) 't': T
[110; 115) '{ t }': T
[112; 113) 't': T
[135; 261) '{ ....x() }': i128
[146; 147) 'x': i32
[150; 151) '1': i32
[162; 163) 'y': i32
[166; 168) 'id': fn id<i32>(T) -> T
[166; 171) 'id(x)': i32
[169; 170) 'x': i32
[182; 183) 'a': A<i32>
[186; 200) 'A { x: id(y) }': A<i32>
[193; 195) 'id': fn id<i32>(T) -> T
[193; 198) 'id(y)': i32
[196; 197) 'y': i32
[211; 212) 'z': i32
[215; 217) 'id': fn id<i32>(T) -> T
[215; 222) 'id(a.x)': i32
[218; 219) 'a': A<i32>
[218; 221) 'a.x': i32
[233; 234) 'b': A<i32>
[237; 247) 'A { x: z }': A<i32>
[244; 245) 'z': i32
[254; 255) 'b': A<i32>
[146; 147) 'x': i128
[150; 151) '1': i128
[162; 163) 'y': i128
[166; 168) 'id': fn id<i128>(T) -> T
[166; 171) 'id(x)': i128
[169; 170) 'x': i128
[182; 183) 'a': A<i128>
[186; 200) 'A { x: id(y) }': A<i128>
[193; 195) 'id': fn id<i128>(T) -> T
[193; 198) 'id(y)': i128
[196; 197) 'y': i128
[211; 212) 'z': i128
[215; 217) 'id': fn id<i128>(T) -> T
[215; 222) 'id(a.x)': i128
[218; 219) 'a': A<i128>
[218; 221) 'a.x': i128
[233; 234) 'b': A<i128>
[237; 247) 'A { x: z }': A<i128>
[244; 245) 'z': i128
[254; 255) 'b': A<i128>
[254; 259) 'b.x()': i128

View File

@ -0,0 +1,39 @@
---
created: "2019-02-16T21:58:14.029368845Z"
creator: insta@0.6.2
source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
---
[74; 78) 'self': A<X, Y>
[85; 107) '{ ... }': X
[95; 99) 'self': A<X, Y>
[95; 101) 'self.x': X
[117; 121) 'self': A<X, Y>
[128; 150) '{ ... }': Y
[138; 142) 'self': A<X, Y>
[138; 144) 'self.y': Y
[163; 167) 'self': A<X, Y>
[169; 170) 't': T
[188; 223) '{ ... }': (X, Y, T)
[198; 217) '(self.....y, t)': (X, Y, T)
[199; 203) 'self': A<X, Y>
[199; 205) 'self.x': X
[207; 211) 'self': A<X, Y>
[207; 213) 'self.y': Y
[215; 216) 't': T
[245; 342) '{ ...(1); }': ()
[255; 256) 'a': A<u64, i64>
[259; 281) 'A { x:...1i64 }': A<u64, i64>
[266; 270) '1u64': u64
[275; 279) '1i64': i64
[287; 288) 'a': A<u64, i64>
[287; 292) 'a.x()': u64
[298; 299) 'a': A<u64, i64>
[298; 303) 'a.y()': i64
[309; 310) 'a': A<u64, i64>
[309; 319) 'a.z(1i128)': (u64, i64, i128)
[313; 318) '1i128': i128
[325; 326) 'a': A<u64, i64>
[325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
[337; 338) '1': u128

View File

@ -0,0 +1,16 @@
---
created: "2019-02-17T13:35:06.385679926Z"
creator: insta@0.6.2
source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
---
[78; 82) 'self': &Option<T>
[98; 100) '{}': ()
[111; 112) 'o': Option<u32>
[127; 165) '{ ...f(); }': ()
[133; 146) '(&o).as_ref()': Option<&u32>
[134; 136) '&o': &Option<u32>
[135; 136) 'o': Option<u32>
[152; 153) 'o': Option<u32>
[152; 162) 'o.as_ref()': Option<&u32>

View File

@ -506,6 +506,58 @@ fn test() {
);
}
#[test]
fn infer_impl_generics() {
check_inference(
"infer_impl_generics",
r#"
struct A<T1, T2> {
x: T1,
y: T2,
}
impl<Y, X> A<X, Y> {
fn x(self) -> X {
self.x
}
fn y(self) -> Y {
self.y
}
fn z<T>(self, t: T) -> (X, Y, T) {
(self.x, self.y, t)
}
}
fn test() -> i128 {
let a = A { x: 1u64, y: 1i64 };
a.x();
a.y();
a.z(1i128);
a.z::<u128>(1);
}
"#,
);
}
#[test]
fn infer_impl_generics_with_autoderef() {
check_inference(
"infer_impl_generics_with_autoderef",
r#"
enum Option<T> {
Some(T),
None,
}
impl<T> Option<T> {
fn as_ref(&self) -> Option<&T> {}
}
fn test(o: Option<u32>) {
(&o).as_ref();
o.as_ref();
}
"#,
);
}
#[test]
fn infer_generic_chain() {
check_inference(

View File

@ -63,7 +63,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
}
fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
receiver.iterate_methods(ctx.db, |func| {
receiver.iterate_methods(ctx.db, |_ty, func| {
let sig = func.signature(ctx.db);
if sig.has_self_param() {
CompletionItem::new(

View File

@ -1352,6 +1352,7 @@ impl ToOwned for ImplBlock {
}
impl ast::TypeParamsOwner for ImplBlock {}
impl ImplBlock {
pub fn item_list(&self) -> Option<&ItemList> {
super::child_opt(self)
@ -2094,6 +2095,10 @@ impl MethodCallExpr {
pub fn name_ref(&self) -> Option<&NameRef> {
super::child_opt(self)
}
pub fn type_arg_list(&self) -> Option<&TypeArgList> {
super::child_opt(self)
}
}
// Module

View File

@ -322,7 +322,7 @@ Grammar(
],
options: ["TypeRef"]
),
"ImplBlock": (options: ["ItemList"]),
"ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner"]),
"ParenType": (options: ["TypeRef"]),
"TupleType": ( collections: [["fields", "TypeRef"]] ),
@ -431,7 +431,7 @@ Grammar(
),
"MethodCallExpr": (
traits: ["ArgListOwner"],
options: [ "Expr", "NameRef" ],
options: [ "Expr", "NameRef", "TypeArgList" ],
),
"IndexExpr": (),
"FieldExpr": (options: ["Expr", "NameRef"]),