hir: lower ImplicitSelf
to resolved Self
TyQPath's.
This commit is contained in:
parent
0807104c8f
commit
6ebb6fdbee
10 changed files with 106 additions and 183 deletions
|
@ -259,7 +259,7 @@ impl<'a> LoweringContext<'a> {
|
|||
P(hir::Ty {
|
||||
id: t.id,
|
||||
node: match t.node {
|
||||
TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
|
||||
TyKind::Infer => hir::TyInfer,
|
||||
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
|
||||
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
|
||||
TyKind::Rptr(ref region, ref mt) => {
|
||||
|
@ -283,6 +283,16 @@ impl<'a> LoweringContext<'a> {
|
|||
TyKind::Path(ref qself, ref path) => {
|
||||
hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
|
||||
}
|
||||
TyKind::ImplicitSelf => {
|
||||
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
|
||||
def: self.expect_full_def(t.id),
|
||||
segments: hir_vec![hir::PathSegment {
|
||||
name: keywords::SelfType.name(),
|
||||
parameters: hir::PathParameters::none()
|
||||
}],
|
||||
span: t.span,
|
||||
})))
|
||||
}
|
||||
TyKind::ObjectSum(ref ty, ref bounds) => {
|
||||
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
|
||||
}
|
||||
|
@ -976,7 +986,7 @@ impl<'a> LoweringContext<'a> {
|
|||
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
|
||||
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
|
||||
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
|
||||
has_self: sig.decl.get_self().is_some(),
|
||||
has_self: sig.decl.has_self(),
|
||||
},
|
||||
ImplItemKind::Macro(..) => unimplemented!(),
|
||||
},
|
||||
|
@ -1051,24 +1061,13 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
|
||||
let hir_sig = hir::MethodSig {
|
||||
hir::MethodSig {
|
||||
generics: self.lower_generics(&sig.generics),
|
||||
abi: sig.abi,
|
||||
unsafety: self.lower_unsafety(sig.unsafety),
|
||||
constness: self.lower_constness(sig.constness),
|
||||
decl: self.lower_fn_decl(&sig.decl),
|
||||
};
|
||||
// Check for `self: _` and `self: &_`
|
||||
if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) {
|
||||
match hir_sig.decl.get_self().map(|eself| eself.node) {
|
||||
Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => {
|
||||
self.diagnostic().span_err(sig.decl.inputs[0].ty.span,
|
||||
"the type placeholder `_` is not allowed within types on item signatures");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
hir_sig
|
||||
}
|
||||
|
||||
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
|
||||
|
|
|
@ -35,8 +35,8 @@ use hir::def_id::DefId;
|
|||
use util::nodemap::{NodeMap, FxHashSet};
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
|
||||
use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
|
||||
use syntax::codemap::{self, respan, Spanned};
|
||||
use syntax_pos::{Span, ExpnId, DUMMY_SP};
|
||||
use syntax::codemap::{self, Spanned};
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
|
||||
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
|
||||
|
@ -1234,37 +1234,8 @@ pub struct Arg {
|
|||
pub id: NodeId,
|
||||
}
|
||||
|
||||
/// Alternative representation for `Arg`s describing `self` parameter of methods.
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum SelfKind {
|
||||
/// `self`, `mut self`
|
||||
Value(Mutability),
|
||||
/// `&'lt self`, `&'lt mut self`
|
||||
Region(Option<Lifetime>, Mutability),
|
||||
/// `self: TYPE`, `mut self: TYPE`
|
||||
Explicit(P<Ty>, Mutability),
|
||||
}
|
||||
|
||||
pub type ExplicitSelf = Spanned<SelfKind>;
|
||||
|
||||
impl Arg {
|
||||
pub fn to_self(&self) -> Option<ExplicitSelf> {
|
||||
if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
|
||||
if name.node == keywords::SelfValue.name() {
|
||||
return match self.ty.node {
|
||||
TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
|
||||
TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
|
||||
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
|
||||
}
|
||||
_ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
|
||||
SelfKind::Explicit(self.ty.clone(), mutbl)))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn is_self(&self) -> bool {
|
||||
fn is_self(&self) -> bool {
|
||||
if let PatKind::Binding(_, _, name, _) = self.pat.node {
|
||||
name.node == keywords::SelfValue.name()
|
||||
} else {
|
||||
|
@ -1282,9 +1253,6 @@ pub struct FnDecl {
|
|||
}
|
||||
|
||||
impl FnDecl {
|
||||
pub fn get_self(&self) -> Option<ExplicitSelf> {
|
||||
self.inputs.get(0).and_then(Arg::to_self)
|
||||
}
|
||||
pub fn has_self(&self) -> bool {
|
||||
self.inputs.get(0).map(Arg::is_self).unwrap_or(false)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ use syntax_pos::{self, BytePos};
|
|||
use errors;
|
||||
|
||||
use hir;
|
||||
use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
|
||||
use hir::{Crate, PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
|
||||
|
||||
use std::io::{self, Write, Read};
|
||||
|
||||
|
@ -1954,27 +1954,6 @@ impl<'a> State<'a> {
|
|||
self.end() // close enclosing cbox
|
||||
}
|
||||
|
||||
fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf) -> io::Result<()> {
|
||||
match explicit_self.node {
|
||||
SelfKind::Value(m) => {
|
||||
self.print_mutability(m)?;
|
||||
word(&mut self.s, "self")
|
||||
}
|
||||
SelfKind::Region(ref lt, m) => {
|
||||
word(&mut self.s, "&")?;
|
||||
self.print_opt_lifetime(lt)?;
|
||||
self.print_mutability(m)?;
|
||||
word(&mut self.s, "self")
|
||||
}
|
||||
SelfKind::Explicit(ref typ, m) => {
|
||||
self.print_mutability(m)?;
|
||||
word(&mut self.s, "self")?;
|
||||
self.word_space(":")?;
|
||||
self.print_type(&typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_fn(&mut self,
|
||||
decl: &hir::FnDecl,
|
||||
unsafety: hir::Unsafety,
|
||||
|
@ -2185,21 +2164,17 @@ impl<'a> State<'a> {
|
|||
match input.ty.node {
|
||||
hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
|
||||
_ => {
|
||||
if let Some(eself) = input.to_self() {
|
||||
self.print_explicit_self(&eself)?;
|
||||
let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
|
||||
name.node == keywords::Invalid.name()
|
||||
} else {
|
||||
let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
|
||||
name.node == keywords::Invalid.name()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !invalid {
|
||||
self.print_pat(&input.pat)?;
|
||||
word(&mut self.s, ":")?;
|
||||
space(&mut self.s)?;
|
||||
}
|
||||
self.print_type(&input.ty)?;
|
||||
false
|
||||
};
|
||||
if !invalid {
|
||||
self.print_pat(&input.pat)?;
|
||||
word(&mut self.s, ":")?;
|
||||
space(&mut self.s)?;
|
||||
}
|
||||
self.print_type(&input.ty)?;
|
||||
}
|
||||
}
|
||||
self.end()
|
||||
|
|
|
@ -2127,7 +2127,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
let (kind, has_self, has_value) = match trait_item.node {
|
||||
hir::MethodTraitItem(ref sig, ref body) => {
|
||||
(AssociatedKind::Method, sig.decl.get_self().is_some(),
|
||||
(AssociatedKind::Method, sig.decl.has_self(),
|
||||
body.is_some())
|
||||
}
|
||||
hir::ConstTraitItem(_, ref value) => {
|
||||
|
|
|
@ -571,6 +571,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
|||
fn visit_ty(&mut self, ty: &'tcx Ty) {
|
||||
if let TyKind::Path(ref qself, ref path) = ty.node {
|
||||
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
||||
} else if let TyKind::ImplicitSelf = ty.node {
|
||||
let self_ty = keywords::SelfType.ident();
|
||||
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
|
||||
.map_or(Def::Err, |d| d.def());
|
||||
self.record_def(ty.id, PathResolution::new(def));
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
|
@ -741,6 +746,13 @@ impl<'a> LexicalScopeBinding<'a> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn def(self) -> Def {
|
||||
match self {
|
||||
LexicalScopeBinding::Item(binding) => binding.def(),
|
||||
LexicalScopeBinding::Def(def) => def,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
use rustc_const_eval::eval_length;
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
use hir::{self, SelfKind};
|
||||
use hir;
|
||||
use hir::def::Def;
|
||||
use hir::def_id::DefId;
|
||||
use hir::print as pprust;
|
||||
|
@ -1743,36 +1743,33 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
// declaration are bound to that function type.
|
||||
let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);
|
||||
|
||||
// `implied_output_region` is the region that will be assumed for any
|
||||
// region parameters in the return type. In accordance with the rules for
|
||||
// lifetime elision, we can determine it in two ways. First (determined
|
||||
// here), if self is by-reference, then the implied output region is the
|
||||
// region of the self parameter.
|
||||
let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
|
||||
(Some(untransformed_self_ty), Some(explicit_self)) => {
|
||||
let self_type = self.determine_self_type(&rb, untransformed_self_ty,
|
||||
&explicit_self);
|
||||
(Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
|
||||
let input_tys: Vec<Ty> =
|
||||
decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
|
||||
|
||||
let has_self = decl.has_self();
|
||||
let explicit_self = match (opt_untransformed_self_ty, has_self) {
|
||||
(Some(untransformed_self_ty), true) => {
|
||||
Some(ExplicitSelf::determine(untransformed_self_ty, input_tys[0]))
|
||||
}
|
||||
_ => (None, None),
|
||||
_ => None
|
||||
};
|
||||
|
||||
// HACK(eddyb) replace the fake self type in the AST with the actual type.
|
||||
let arg_params = if self_ty.is_some() {
|
||||
&decl.inputs[1..]
|
||||
} else {
|
||||
&decl.inputs[..]
|
||||
};
|
||||
let arg_tys: Vec<Ty> =
|
||||
arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
|
||||
|
||||
// Second, if there was exactly one lifetime (either a substitution or a
|
||||
// reference) in the arguments, then any anonymous regions in the output
|
||||
// have that lifetime.
|
||||
let implied_output_region = match explicit_self {
|
||||
// `implied_output_region` is the region that will be assumed for any
|
||||
// region parameters in the return type. In accordance with the rules for
|
||||
// lifetime elision, we can determine it in two ways. First (determined
|
||||
// here), if self is by-reference, then the implied output region is the
|
||||
// region of the self parameter.
|
||||
Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),
|
||||
|
||||
// Second, if there was exactly one lifetime (either a substitution or a
|
||||
// reference) in the arguments, then any anonymous regions in the output
|
||||
// have that lifetime.
|
||||
_ => {
|
||||
self.find_implied_output_region(&arg_tys,
|
||||
let arg_params = &decl.inputs[has_self as usize..];
|
||||
let arg_tys = &input_tys[has_self as usize..];
|
||||
|
||||
self.find_implied_output_region(arg_tys,
|
||||
arg_params.iter()
|
||||
.map(|a| pprust::pat_to_string(&a.pat)))
|
||||
|
||||
|
@ -1793,37 +1790,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
unsafety: unsafety,
|
||||
abi: abi,
|
||||
sig: ty::Binder(self.tcx().mk_fn_sig(
|
||||
self_ty.into_iter().chain(arg_tys),
|
||||
input_tys.into_iter(),
|
||||
output_ty,
|
||||
decl.variadic
|
||||
)),
|
||||
})
|
||||
}
|
||||
|
||||
fn determine_self_type<'a>(&self,
|
||||
rscope: &RegionScope,
|
||||
untransformed_self_ty: Ty<'tcx>,
|
||||
explicit_self: &hir::ExplicitSelf)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
match explicit_self.node {
|
||||
SelfKind::Value(..) => untransformed_self_ty,
|
||||
SelfKind::Region(ref lifetime, mutability) => {
|
||||
let region =
|
||||
self.opt_ast_region_to_region(
|
||||
rscope,
|
||||
explicit_self.span,
|
||||
lifetime);
|
||||
self.tcx().mk_ref(region,
|
||||
ty::TypeAndMut {
|
||||
ty: untransformed_self_ty,
|
||||
mutbl: mutability
|
||||
})
|
||||
}
|
||||
SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_of_closure(&self,
|
||||
unsafety: hir::Unsafety,
|
||||
decl: &hir::FnDecl,
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::hir::{self, ImplItemKind, TraitItem_};
|
||||
use rustc::infer::{self, InferOk};
|
||||
use rustc::middle::free_region::FreeRegionMap;
|
||||
use rustc::ty;
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
|
||||
use rustc::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
|
||||
use rustc::util::common::ErrorReported;
|
||||
|
||||
use syntax::ast;
|
||||
|
@ -456,31 +455,18 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
|
|||
_ => bug!("{:?} is not a MethodTraitItem", trait_m),
|
||||
};
|
||||
|
||||
impl_m_iter.zip(trait_m_iter)
|
||||
.find(|&(ref impl_arg, ref trait_arg)| {
|
||||
match (&impl_arg.ty.node, &trait_arg.ty.node) {
|
||||
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
|
||||
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
|
||||
impl_mt.mutbl != trait_mt.mutbl
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.map(|(ref impl_arg, ref trait_arg)| {
|
||||
match (impl_arg.to_self(), trait_arg.to_self()) {
|
||||
(Some(impl_self), Some(trait_self)) => {
|
||||
(impl_self.span, Some(trait_self.span))
|
||||
}
|
||||
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
|
||||
_ => {
|
||||
bug!("impl and trait fns have different first args, impl: \
|
||||
{:?}, trait: {:?}",
|
||||
impl_arg,
|
||||
trait_arg)
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
|
||||
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
|
||||
match (&impl_arg.ty.node, &trait_arg.ty.node) {
|
||||
(&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
|
||||
(&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
|
||||
impl_mt.mutbl != trait_mt.mutbl
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}).map(|(ref impl_arg, ref trait_arg)| {
|
||||
(impl_arg.ty.span, Some(trait_arg.ty.span))
|
||||
})
|
||||
.unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
|
||||
} else {
|
||||
(cause.span, tcx.map.span_if_local(trait_m.def_id))
|
||||
}
|
||||
|
|
|
@ -1184,16 +1184,17 @@ pub enum SelfTy {
|
|||
|
||||
impl Argument {
|
||||
pub fn to_self(&self) -> Option<SelfTy> {
|
||||
if self.name == "self" {
|
||||
match self.type_ {
|
||||
Infer => Some(SelfValue),
|
||||
BorrowedRef{ref lifetime, mutability, ref type_} if **type_ == Infer => {
|
||||
Some(SelfBorrowed(lifetime.clone(), mutability))
|
||||
}
|
||||
_ => Some(SelfExplicit(self.type_.clone()))
|
||||
if self.name != "self" {
|
||||
return None;
|
||||
}
|
||||
if self.type_.is_self_type() {
|
||||
return Some(SelfValue);
|
||||
}
|
||||
match self.type_ {
|
||||
BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
|
||||
Some(SelfBorrowed(lifetime.clone(), mutability))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
_ => Some(SelfExplicit(self.type_.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1353,11 +1354,13 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
|
|||
};
|
||||
let self_arg_ty = *fty.sig.input(0).skip_binder();
|
||||
if self_arg_ty == self_ty {
|
||||
decl.inputs.values[0].type_ = Infer;
|
||||
decl.inputs.values[0].type_ = Generic(String::from("Self"));
|
||||
} else if let ty::TyRef(_, mt) = self_arg_ty.sty {
|
||||
if mt.ty == self_ty {
|
||||
match decl.inputs.values[0].type_ {
|
||||
BorrowedRef{ref mut type_, ..} => **type_ = Infer,
|
||||
BorrowedRef{ref mut type_, ..} => {
|
||||
**type_ = Generic(String::from("Self"))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1568,6 +1571,13 @@ impl Type {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_self_type(&self) -> bool {
|
||||
match *self {
|
||||
Generic(ref name) => name == "Self",
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GetDefId for Type {
|
||||
|
|
|
@ -1471,12 +1471,13 @@ impl Arg {
|
|||
}
|
||||
|
||||
pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
|
||||
let span = mk_sp(eself.span.lo, eself_ident.span.hi);
|
||||
let infer_ty = P(Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
node: TyKind::ImplicitSelf,
|
||||
span: DUMMY_SP,
|
||||
span: span,
|
||||
});
|
||||
let arg = |mutbl, ty, span| Arg {
|
||||
let arg = |mutbl, ty| Arg {
|
||||
pat: P(Pat {
|
||||
id: DUMMY_NODE_ID,
|
||||
node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
|
||||
|
@ -1486,15 +1487,13 @@ impl Arg {
|
|||
id: DUMMY_NODE_ID,
|
||||
};
|
||||
match eself.node {
|
||||
SelfKind::Explicit(ty, mutbl) => {
|
||||
arg(mutbl, ty, mk_sp(eself.span.lo, eself_ident.span.hi))
|
||||
}
|
||||
SelfKind::Value(mutbl) => arg(mutbl, infer_ty, eself.span),
|
||||
SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty),
|
||||
SelfKind::Value(mutbl) => arg(mutbl, infer_ty),
|
||||
SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }),
|
||||
span: DUMMY_SP,
|
||||
}), eself.span),
|
||||
span: span,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
|
||||
|
||||
fn foo_method(&self) -> &'static str { return "i am very similar to foo."; }
|
||||
/* nest::{{impl}}::foo_method */
|
||||
fn foo_method(self: &Self)
|
||||
-> &'static str { return "i am very similar to foo."; } /*
|
||||
nest::{{impl}}::foo_method */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue