aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-02-03 16:45:27 +0000
committerPhilip Herron <herron.philip@googlemail.com>2021-02-06 15:45:51 +0000
commit34a39466b2adb9684a1737c6ea4915e0194c26bf (patch)
treedf65323e28a0b4507431969d62ac932fc2efb2d3
parent59a8fa1a80c3b2c6520c627a6bf200274732d395 (diff)
downloadgcc-34a39466b2adb9684a1737c6ea4915e0194c26bf.zip
gcc-34a39466b2adb9684a1737c6ea4915e0194c26bf.tar.gz
gcc-34a39466b2adb9684a1737c6ea4915e0194c26bf.tar.bz2
Add in support to compile Methods and MethodCallExpr
There is more work to be done here with adjustments to the self argument such as borrows and mutability checking. Method resolution is basic, for now there is code to scan for all possible matches but traits are not supported at the moment so this resolves quite simply for now. Fixes #191 #112
-rw-r--r--gcc/rust/ast/rust-expr.h13
-rw-r--r--gcc/rust/ast/rust-item.h19
-rw-r--r--gcc/rust/ast/rust-pattern.h11
-rw-r--r--gcc/rust/backend/cscope.h160
-rw-r--r--gcc/rust/backend/rust-compile-expr.h2
-rw-r--r--gcc/rust/backend/rust-compile-fnparam.h16
-rw-r--r--gcc/rust/backend/rust-compile-implitem.h232
-rw-r--r--gcc/rust/backend/rust-compile-item.h13
-rw-r--r--gcc/rust/backend/rust-compile.cc77
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h29
-rw-r--r--gcc/rust/hir/rust-ast-lower-implitem.h100
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h25
-rw-r--r--gcc/rust/hir/tree/rust-hir-full-test.cc2
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h99
-rw-r--r--gcc/rust/hir/tree/rust-hir-path.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h9
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h52
-rw-r--r--gcc/rust/typecheck/rust-hir-method-resolve.h95
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h81
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h105
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-toplevel.h10
-rw-r--r--gcc/rust/typecheck/rust-tycheck-dump.h12
-rw-r--r--gcc/rust/typecheck/rust-tyty-call.h42
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc64
-rw-r--r--gcc/rust/util/rust-hir-map.cc24
-rw-r--r--gcc/rust/util/rust-hir-map.h19
-rw-r--r--gcc/testsuite/rust.test/compilable/methods1.rs39
-rw-r--r--gcc/testsuite/rust.test/compilable/methods2.rs41
28 files changed, 1170 insertions, 223 deletions
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 6dba7fd..50006d1 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -2355,9 +2355,9 @@ public:
void iterate_params (std::function<bool (Expr *)> cb)
{
- for (auto it = params.begin (); it != params.end (); it++)
+ for (auto &param : params)
{
- if (!cb (it->get ()))
+ if (!cb (param.get ()))
return;
}
}
@@ -2456,6 +2456,15 @@ public:
void mark_for_strip () override { receiver = nullptr; }
bool is_marked_for_strip () const override { return receiver == nullptr; }
+ void iterate_params (std::function<bool (Expr *)> cb)
+ {
+ for (auto &param : params)
+ {
+ if (!cb (param.get ()))
+ return;
+ }
+ }
+
// TODO: this mutable getter seems really dodgy. Think up better way.
const std::vector<std::unique_ptr<Expr> > &get_params () const
{
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index ecfc310..352fabc 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -366,12 +366,14 @@ private:
// bool has_type; // only possible if not ref
std::unique_ptr<Type> type;
+ NodeId node_id;
+
Location locus;
// Unrestricted constructor used for error state
SelfParam (Lifetime lifetime, bool has_ref, bool is_mut, Type *type)
: has_ref (has_ref), is_mut (is_mut), lifetime (std::move (lifetime)),
- type (type)
+ type (type), node_id (Analysis::Mappings::get ()->get_next_node_id ())
{}
// this is ok as no outside classes can ever call this
@@ -401,20 +403,23 @@ public:
// Type-based self parameter (not ref, no lifetime)
SelfParam (std::unique_ptr<Type> type, bool is_mut, Location locus)
: has_ref (false), is_mut (is_mut), lifetime (Lifetime::error ()),
- type (std::move (type)), locus (locus)
+ type (std::move (type)),
+ node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus)
{}
// Lifetime-based self parameter (is ref, no type)
SelfParam (Lifetime lifetime, bool is_mut, Location locus)
: has_ref (true), is_mut (is_mut), lifetime (std::move (lifetime)),
- locus (locus)
+ node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus)
{}
// Copy constructor requires clone
SelfParam (SelfParam const &other)
: has_ref (other.has_ref), is_mut (other.is_mut), lifetime (other.lifetime),
+ node_id (Analysis::Mappings::get ()->get_next_node_id ()),
locus (other.locus)
{
+ node_id = other.node_id;
if (other.type != nullptr)
type = other.type->clone_type ();
}
@@ -426,6 +431,7 @@ public:
has_ref = other.has_ref;
lifetime = other.lifetime;
locus = other.locus;
+ node_id = other.node_id;
if (other.type != nullptr)
type = other.type->clone_type ();
@@ -443,6 +449,13 @@ public:
Location get_locus () const { return locus; }
+ bool get_has_ref () const { return has_ref; };
+ bool get_is_mut () const { return is_mut; }
+
+ Lifetime get_lifetime () const { return lifetime; }
+
+ NodeId get_node_id () const { return node_id; }
+
// TODO: is this better? Or is a "vis_block" better?
std::unique_ptr<Type> &get_type ()
{
diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h
index e89fc62..049aaf0 100644
--- a/gcc/rust/ast/rust-pattern.h
+++ b/gcc/rust/ast/rust-pattern.h
@@ -78,7 +78,7 @@ class IdentifierPattern : public Pattern
Location locus;
public:
- std::string as_string () const;
+ std::string as_string () const override;
// Returns whether the IdentifierPattern has a pattern to bind.
bool has_pattern_to_bind () const { return to_bind != nullptr; }
@@ -91,6 +91,15 @@ public:
is_mut (is_mut), to_bind (std::move (to_bind)), locus (locus)
{}
+ IdentifierPattern (NodeId node_id, Identifier ident, Location locus,
+ bool is_ref = false, bool is_mut = false,
+ std::unique_ptr<Pattern> to_bind = nullptr)
+ : Pattern (), variable_ident (std::move (ident)), is_ref (is_ref),
+ is_mut (is_mut), to_bind (std::move (to_bind)), locus (locus)
+ {
+ this->node_id = node_id;
+ }
+
// Copy constructor with clone
IdentifierPattern (IdentifierPattern const &other)
: variable_ident (other.variable_ident), is_ref (other.is_ref),
diff --git a/gcc/rust/backend/cscope.h b/gcc/rust/backend/cscope.h
deleted file mode 100644
index 3ba837c..0000000
--- a/gcc/rust/backend/cscope.h
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (C) 2020 Free Software Foundation, Inc.
-
-// This file is part of GCC.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with GCC; see the file COPYING3. If not see
-// <http://www.gnu.org/licenses/>.
-
-#pragma once
-
-#include "rust-system.h"
-#include "rust-backend.h"
-#include "scope.h"
-
-namespace Rust {
-namespace Compile {
-
-class Scope
-{
-public:
- Scope (Backend *backend) : backend (backend) {}
-
- ~Scope () {}
-
- void Push ()
- {
- fndecls.Push ();
- vars.Push ();
- types.Push ();
- structDecls.Push ();
- }
-
- void Pop ()
- {
- fndecls.Pop ();
- vars.Pop ();
- types.Pop ();
- structDecls.Pop ();
- }
-
- void PushCurrentFunction (std::string name, Bfunction *fn, Btype *retType,
- Bvariable *retDecl)
- {
- fns.push_back (fn);
- fnRetType.push_back (retType);
- fnRetDecl.push_back (retDecl);
- }
-
- Bfunction *PopCurrentFunction ()
- {
- auto ret = fns.back ();
- fns.pop_back ();
- fnRetType.pop_back ();
- fnRetDecl.pop_back ();
- return ret;
- }
-
- Bfunction *GetCurrentFndecl () { return fns.back (); }
-
- Btype *GetCurrentFnRetType () { return fnRetType.back (); }
-
- Bvariable *GetCurrentFnRetDecl () { return fnRetDecl.back (); }
-
- Btype *GetFnRetType (Bfunction *fn)
- {
- auto it = fnRetTypeMapping.find (fn);
- if (it == fnRetTypeMapping.end ())
- {
- return NULL;
- }
- return it->second;
- }
-
- void PushBlock (Bblock *block)
- {
- blocks.push_back (block);
- std::vector<Bstatement *> empty;
- context.push_back (empty);
- }
-
- Bblock *PopBlock ()
- {
- auto ret = blocks.back ();
- blocks.pop_back ();
-
- auto stmts = context.back ();
- context.pop_back ();
-
- backend->block_add_statements (ret, stmts);
-
- return ret;
- }
-
- Bblock *CurBlock () { return blocks.back (); }
-
- void AddStatement (Bstatement *stmt) { context.back ().push_back (stmt); }
-
- void InsertStructDecl (std::string name, AST::StructStruct *decl)
- {
- structDecls.Insert (name, decl);
- }
-
- bool LookupStructDecl (std::string name, AST::StructStruct **decl)
- {
- return structDecls.Lookup (name, decl);
- }
-
- void InsertFunction (std::string name, Bfunction *fn, Btype *retType)
- {
- fndecls.Insert (name, fn);
- fnRetTypeMapping[fn] = retType;
- }
-
- bool LookupFunction (std::string name, Bfunction **fn)
- {
- return fndecls.Lookup (name, fn);
- }
-
- void InsertType (std::string name, Btype *type) { types.Insert (name, type); }
-
- bool LookupType (std::string name, Btype **type)
- {
- return types.Lookup (name, type);
- }
-
- void InsertVar (std::string name, Bvariable *var) { vars.Insert (name, var); }
-
- bool LookupVar (std::string name, Bvariable **var)
- {
- return vars.Lookup (name, var);
- }
-
-private:
- Backend *backend;
-
- ::std::vector<Bfunction *> fns;
- ::std::vector<Bblock *> blocks;
- ::std::vector< ::std::vector<Bstatement *> > context;
- ::std::vector< ::Btype *> fnRetType;
- ::std::vector< ::Bvariable *> fnRetDecl;
- ::std::map<Bfunction *, Btype *> fnRetTypeMapping;
-
- Analysis::Scope<Bfunction *> fndecls;
- Analysis::Scope<Bvariable *> vars;
- Analysis::Scope<Btype *> types;
- Analysis::Scope<AST::StructStruct *> structDecls;
-};
-
-} // namespace Compile
-} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index fad5ce0..b823d29 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -99,6 +99,8 @@ public:
void visit (HIR::CallExpr &expr);
+ void visit (HIR::MethodCallExpr &expr);
+
void visit (HIR::IdentifierExpr &expr)
{
// need to look up the reference for this identifier
diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h
index cf6e6f7..1ea0c9f 100644
--- a/gcc/rust/backend/rust-compile-fnparam.h
+++ b/gcc/rust/backend/rust-compile-fnparam.h
@@ -61,6 +61,22 @@ private:
::Bvariable *translated;
};
+class CompileSelfParam : public HIRCompileBase
+{
+public:
+ static Bvariable *compile (Context *ctx, Bfunction *fndecl,
+ HIR::SelfParam &self, Btype *decl_type,
+ Location locus)
+ {
+ if (!self.get_is_mut ())
+ decl_type = ctx->get_backend ()->immutable_type (decl_type);
+
+ return ctx->get_backend ()->parameter_variable (fndecl, "self", decl_type,
+ false /* address_taken */,
+ locus);
+ }
+};
+
} // namespace Compile
} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h
index 8286a5c..6d180c8 100644
--- a/gcc/rust/backend/rust-compile-implitem.h
+++ b/gcc/rust/backend/rust-compile-implitem.h
@@ -32,10 +32,10 @@ namespace Compile {
class CompileInherentImplItem : public HIRCompileBase
{
public:
- static void Compile (HIR::Type *base, HIR::InherentImplItem *item,
+ static void Compile (TyTy::TyBase *self, HIR::InherentImplItem *item,
Context *ctx, bool compile_fns)
{
- CompileInherentImplItem compiler (base, ctx, compile_fns);
+ CompileInherentImplItem compiler (self, ctx, compile_fns);
item->accept_vis (compiler);
}
@@ -50,7 +50,7 @@ public:
::Btype *type = TyTyResolveCompile::compile (ctx, resolved_type);
Bexpression *value = CompileExpr::Compile (constant.get_expr (), ctx);
- std::string ident = base->as_string () + "::" + constant.get_identifier ();
+ std::string ident = self->as_string () + "::" + constant.get_identifier ();
Bexpression *const_expr = ctx->get_backend ()->named_constant_expression (
type, constant.get_identifier (), value, constant.get_locus ());
@@ -78,7 +78,8 @@ public:
if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hirid (),
&fntype_tyty))
{
- rust_fatal_error (function.locus, "failed to lookup function type");
+ rust_fatal_error (function.get_locus (),
+ "failed to lookup function type");
return;
}
@@ -93,23 +94,15 @@ public:
::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
unsigned int flags = 0;
- bool is_main_fn = function.function_name.compare ("main") == 0;
-
std::string fn_identifier
- = base->as_string () + "::" + function.function_name;
+ = self->as_string () + "::" + function.function_name;
// if its the main fn or pub visibility mark its as DECL_PUBLIC
// please see https://github.com/Rust-GCC/gccrs/pull/137
- if (is_main_fn || function.has_visibility ())
+ if (function.has_visibility ())
flags |= Backend::function_is_visible;
std::string asm_name = fn_identifier;
- if (!is_main_fn)
- {
- // FIXME need name mangling
- asm_name = "__" + function.function_name;
- }
-
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, fn_identifier,
asm_name, flags, function.get_locus ());
@@ -229,12 +222,217 @@ public:
ctx->push_function (fndecl);
}
+ void visit (HIR::Method &method)
+ {
+ if (!compile_fns)
+ return;
+
+ // items can be forward compiled which means we may not need to invoke this
+ // code
+ Bfunction *lookup = nullptr;
+ if (ctx->lookup_function_decl (method.get_mappings ().get_hirid (),
+ &lookup))
+ {
+ // has this been added to the list then it must be finished
+ if (ctx->function_completed (lookup))
+ return;
+ }
+
+ TyTy::TyBase *fntype_tyty;
+ if (!ctx->get_tyctx ()->lookup_type (method.get_mappings ().get_hirid (),
+ &fntype_tyty))
+ {
+ rust_fatal_error (method.get_locus (),
+ "failed to lookup function type");
+ return;
+ }
+
+ if (fntype_tyty->get_kind () != TyTy::TypeKind::FNDEF)
+ {
+ rust_error_at (method.get_locus (), "invalid TyTy for function item");
+ return;
+ }
+
+ TyTy::FnType *fntype = (TyTy::FnType *) fntype_tyty;
+ // convert to the actual function type
+ ::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
+
+ unsigned int flags = 0;
+ std::string fn_identifier
+ = self->as_string () + "::" + method.get_method_name ();
+
+ // if its the main fn or pub visibility mark its as DECL_PUBLIC
+ // please see https://github.com/Rust-GCC/gccrs/pull/137
+ if (method.has_visibility ())
+ flags |= Backend::function_is_visible;
+
+ std::string asm_name = fn_identifier;
+ Bfunction *fndecl
+ = ctx->get_backend ()->function (compiled_fn_type, fn_identifier,
+ asm_name, flags, method.get_locus ());
+ ctx->insert_function_decl (method.get_mappings ().get_hirid (), fndecl);
+
+ // setup the params
+ TyTy::TyBase *tyret = fntype->return_type ();
+ std::vector<Bvariable *> param_vars;
+
+ // insert self
+ TyTy::TyBase *self_tyty_lookup = nullptr;
+ if (!ctx->get_tyctx ()->lookup_type (
+ method.get_self_param ().get_mappings ().get_hirid (),
+ &self_tyty_lookup))
+ {
+ rust_error_at (method.get_self_param ().get_locus (),
+ "failed to lookup self param type");
+ return;
+ }
+
+ Btype *self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup);
+ if (self_type == nullptr)
+ {
+ rust_error_at (method.get_self_param ().get_locus (),
+ "failed to compile self param type");
+ return;
+ }
+
+ Bvariable *compiled_self_param
+ = CompileSelfParam::compile (ctx, fndecl, method.get_self_param (),
+ self_type,
+ method.get_self_param ().get_locus ());
+ if (compiled_self_param == nullptr)
+ {
+ rust_error_at (method.get_self_param ().get_locus (),
+ "failed to compile self param variable");
+ return;
+ }
+
+ param_vars.push_back (compiled_self_param);
+ ctx->insert_var_decl (method.get_self_param ().get_mappings ().get_hirid (),
+ compiled_self_param);
+
+ // offset from + 1 for the TyTy::FnType being used
+ size_t i = 1;
+ for (auto referenced_param : method.get_function_params ())
+ {
+ auto tyty_param = fntype->param_at (i);
+ auto param_tyty = tyty_param.second;
+
+ auto compiled_param_type
+ = TyTyResolveCompile::compile (ctx, param_tyty);
+ if (compiled_param_type == nullptr)
+ {
+ rust_error_at (referenced_param.get_locus (),
+ "failed to compile parameter type");
+ return;
+ }
+
+ Location param_locus
+ = ctx->get_mappings ()->lookup_location (param_tyty->get_ref ());
+ Bvariable *compiled_param_var
+ = CompileFnParam::compile (ctx, fndecl, &referenced_param,
+ compiled_param_type, param_locus);
+ if (compiled_param_var == nullptr)
+ {
+ rust_error_at (param_locus, "failed to compile parameter variable");
+ return;
+ }
+
+ param_vars.push_back (compiled_param_var);
+
+ ctx->insert_var_decl (referenced_param.get_mappings ().get_hirid (),
+ compiled_param_var);
+ i++;
+ }
+
+ if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
+ {
+ rust_fatal_error (method.get_locus (),
+ "failed to setup parameter variables");
+ return;
+ }
+
+ // lookup locals
+ auto block_expr = method.get_function_body ().get ();
+ auto body_mappings = block_expr->get_mappings ();
+
+ Resolver::Rib *rib = nullptr;
+ if (!ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (),
+ &rib))
+ {
+ rust_fatal_error (method.get_locus (),
+ "failed to setup locals per block");
+ return;
+ }
+
+ std::vector<Bvariable *> locals;
+ rib->iterate_decls ([&] (NodeId n, Location) mutable -> bool {
+ Resolver::Definition d;
+ bool ok = ctx->get_resolver ()->lookup_definition (n, &d);
+ rust_assert (ok);
+
+ HIR::Stmt *decl = nullptr;
+ ok = ctx->get_mappings ()->resolve_nodeid_to_stmt (d.parent, &decl);
+ rust_assert (ok);
+
+ Bvariable *compiled = CompileVarDecl::compile (fndecl, decl, ctx);
+ locals.push_back (compiled);
+
+ return true;
+ });
+
+ bool toplevel_item
+ = method.get_mappings ().get_local_defid () != UNKNOWN_LOCAL_DEFID;
+ Bblock *enclosing_scope
+ = toplevel_item ? NULL : ctx->peek_enclosing_scope ();
+
+ HIR::BlockExpr *function_body = method.get_function_body ().get ();
+ Location start_location = function_body->get_locus ();
+ Location end_location = function_body->get_closing_locus ();
+
+ Bblock *code_block
+ = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
+ start_location, end_location);
+ ctx->push_block (code_block);
+
+ Bvariable *return_address = nullptr;
+ if (method.has_function_return_type ())
+ {
+ Btype *return_type = TyTyResolveCompile::compile (ctx, tyret);
+
+ bool address_is_taken = false;
+ Bstatement *ret_var_stmt = nullptr;
+
+ return_address = ctx->get_backend ()->temporary_variable (
+ fndecl, code_block, return_type, NULL, address_is_taken,
+ method.get_locus (), &ret_var_stmt);
+
+ ctx->add_statement (ret_var_stmt);
+ }
+
+ ctx->push_fn (fndecl, return_address);
+
+ compile_function_body (fndecl, method.get_function_body (),
+ method.has_function_return_type ());
+
+ ctx->pop_block ();
+ auto body = ctx->get_backend ()->block_statement (code_block);
+ if (!ctx->get_backend ()->function_set_body (fndecl, body))
+ {
+ rust_error_at (method.get_locus (), "failed to set body to function");
+ return;
+ }
+
+ ctx->pop_fn ();
+
+ ctx->push_function (fndecl);
+ }
+
private:
- CompileInherentImplItem (HIR::Type *base, Context *ctx, bool compile_fns)
- : HIRCompileBase (ctx), base (base), compile_fns (compile_fns)
+ CompileInherentImplItem (TyTy::TyBase *self, Context *ctx, bool compile_fns)
+ : HIRCompileBase (ctx), self (self), compile_fns (compile_fns)
{}
- HIR::Type *base;
+ TyTy::TyBase *self;
bool compile_fns;
};
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h
index b08c49e..7f93af9f 100644
--- a/gcc/rust/backend/rust-compile-item.h
+++ b/gcc/rust/backend/rust-compile-item.h
@@ -282,9 +282,18 @@ public:
void visit (HIR::InherentImpl &impl_block)
{
+ TyTy::TyBase *self_lookup = nullptr;
+ if (!ctx->get_tyctx ()->lookup_type (
+ impl_block.get_type ()->get_mappings ().get_hirid (), &self_lookup))
+ {
+ rust_error_at (impl_block.get_locus (),
+ "failed to resolve type of impl");
+ return;
+ }
+
for (auto &impl_item : impl_block.get_impl_items ())
- CompileInherentImplItem::Compile (impl_block.get_type ().get (),
- impl_item.get (), ctx, compile_fns);
+ CompileInherentImplItem::Compile (self_lookup, impl_item.get (), ctx,
+ compile_fns);
}
private:
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index f72cf4c..0b83c72 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -95,6 +95,83 @@ CompileExpr::visit (HIR::CallExpr &expr)
}
}
+void
+CompileExpr::visit (HIR::MethodCallExpr &expr)
+{
+ // lookup the resolved name
+ NodeId resolved_node_id = UNKNOWN_NODEID;
+ if (!ctx->get_resolver ()->lookup_resolved_name (
+ expr.get_mappings ().get_nodeid (), &resolved_node_id))
+ {
+ rust_error_at (expr.get_locus (), "failed to lookup resolved MethodCall");
+ return;
+ }
+
+ // reverse lookup
+ HirId ref;
+ if (!ctx->get_mappings ()->lookup_node_to_hir (
+ expr.get_mappings ().get_crate_num (), resolved_node_id, &ref))
+ {
+ rust_fatal_error (expr.get_locus (), "reverse lookup failure");
+ return;
+ }
+
+ // lookup compiled functions
+ Bfunction *fn = nullptr;
+ if (!ctx->lookup_function_decl (ref, &fn))
+ {
+ // this might fail because its a forward decl so we can attempt to
+ // resolve it now
+ HIR::InherentImplItem *resolved_item
+ = ctx->get_mappings ()->lookup_hir_implitem (
+ expr.get_mappings ().get_crate_num (), ref);
+ if (resolved_item == nullptr)
+ {
+ rust_error_at (expr.get_locus (), "failed to lookup forward decl");
+ return;
+ }
+
+ TyTy::TyBase *self_type = nullptr;
+ if (!ctx->get_tyctx ()->lookup_type (
+ expr.get_receiver ()->get_mappings ().get_hirid (), &self_type))
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to resolve type for self param");
+ return;
+ }
+
+ CompileInherentImplItem::Compile (self_type, resolved_item, ctx, true);
+ if (!ctx->lookup_function_decl (ref, &fn))
+ {
+ rust_error_at (expr.get_locus (), "forward decl was not compiled");
+ return;
+ }
+ }
+
+ Bexpression *fn_expr
+ = ctx->get_backend ()->function_code_expression (fn, expr.get_locus ());
+
+ std::vector<Bexpression *> args;
+
+ // method receiver
+ Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
+ rust_assert (self != nullptr);
+ args.push_back (self);
+
+ // normal args
+ expr.iterate_params ([&] (HIR::Expr *p) mutable -> bool {
+ Bexpression *compiled_expr = CompileExpr::Compile (p, ctx);
+ rust_assert (compiled_expr != nullptr);
+ args.push_back (compiled_expr);
+ return true;
+ });
+
+ auto fncontext = ctx->peek_fn ();
+ translated
+ = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_expr, args,
+ nullptr, expr.get_locus ());
+}
+
// rust-compile-block.h
void
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h
index fc18e27..cd1863f 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.h
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -238,6 +238,35 @@ public:
expr.get_locus ());
}
+ void visit (AST::MethodCallExpr &expr)
+ {
+ std::vector<HIR::Attribute> outer_attribs;
+
+ HIR::PathExprSegment method_path (
+ expr.get_method_name ().get_ident_segment ().as_string (),
+ expr.get_method_name ().get_locus ());
+
+ HIR::Expr *receiver
+ = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ());
+
+ std::vector<std::unique_ptr<HIR::Expr> > params;
+ expr.iterate_params ([&] (AST::Expr *p) mutable -> bool {
+ auto trans = ASTLoweringExpr::translate (p);
+ params.push_back (std::unique_ptr<HIR::Expr> (trans));
+ return true;
+ });
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (
+ crate_num, UNKNOWN_NODEID /* this can map back to the AST*/,
+ mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+ translated
+ = new HIR::MethodCallExpr (mapping, std::unique_ptr<HIR::Expr> (receiver),
+ method_path, std::move (params),
+ std::move (outer_attribs), expr.get_locus ());
+ }
+
void visit (AST::AssignmentExpr &expr)
{
HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ());
diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h
index dab3208..de4d55d 100644
--- a/gcc/rust/hir/rust-ast-lower-implitem.h
+++ b/gcc/rust/hir/rust-ast-lower-implitem.h
@@ -40,6 +40,21 @@ public:
return resolver.translated;
}
+ HIR::SelfParam lower_self (AST::SelfParam &self)
+ {
+ HIR::Type *type = self.has_type ()
+ ? ASTLoweringType::translate (self.get_type ().get ())
+ : nullptr;
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, self.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (crate_num));
+
+ return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (type),
+ self.get_is_mut (), self.get_locus ());
+ }
+
void visit (AST::ConstantItem &constant)
{
std::vector<HIR::Attribute> outer_attrs;
@@ -143,6 +158,91 @@ public:
translated = fn;
}
+ void visit (AST::Method &method)
+ {
+ // ignore for now and leave empty
+ std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+ std::vector<HIR::Attribute> outer_attrs;
+ std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+ HIR::WhereClause where_clause (std::move (where_clause_items));
+ HIR::FunctionQualifiers qualifiers (
+ HIR::FunctionQualifiers::AsyncConstStatus::NONE, false);
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+
+ // need
+ Identifier method_name = method.get_method_name ();
+ Location locus = method.get_locus ();
+
+ HIR::SelfParam self_param = lower_self (method.get_self_param ());
+
+ std::unique_ptr<HIR::Type> return_type
+ = method.has_return_type () ? std::unique_ptr<HIR::Type> (
+ ASTLoweringType::translate (method.get_return_type ().get ()))
+ : nullptr;
+
+ std::vector<HIR::FunctionParam> function_params;
+ for (auto &param : method.get_function_params ())
+ {
+ auto translated_pattern = std::unique_ptr<HIR::Pattern> (
+ ASTLoweringPattern::translate (param.get_pattern ().get ()));
+ auto translated_type = std::unique_ptr<HIR::Type> (
+ ASTLoweringType::translate (param.get_type ().get ()));
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ auto hir_param
+ = HIR::FunctionParam (mapping, std::move (translated_pattern),
+ std::move (translated_type),
+ param.get_locus ());
+ function_params.push_back (hir_param);
+ }
+
+ bool terminated = false;
+ std::unique_ptr<HIR::BlockExpr> method_body
+ = std::unique_ptr<HIR::BlockExpr> (
+ ASTLoweringBlock::translate (method.get_definition ().get (),
+ &terminated));
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, method.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (crate_num));
+ auto mth
+ = new HIR::Method (mapping, std::move (method_name),
+ std::move (qualifiers), std::move (generic_params),
+ std::move (self_param), std::move (function_params),
+ std::move (return_type), std::move (where_clause),
+ std::move (method_body), std::move (vis),
+ std::move (outer_attrs), locus);
+
+ mappings->insert_hir_implitem (mapping.get_crate_num (),
+ mapping.get_hirid (), mth);
+ mappings->insert_location (crate_num, mapping.get_hirid (),
+ method.get_locus ());
+
+ // insert mappings for self
+ mappings->insert_hir_self_param (crate_num,
+ self_param.get_mappings ().get_hirid (),
+ &self_param);
+ mappings->insert_location (crate_num,
+ self_param.get_mappings ().get_hirid (),
+ self_param.get_locus ());
+
+ // add the mappings for the function params at the end
+ for (auto &param : mth->get_function_params ())
+ {
+ mappings->insert_hir_param (mapping.get_crate_num (),
+ param.get_mappings ().get_hirid (), &param);
+ mappings->insert_location (crate_num, mapping.get_hirid (),
+ param.get_locus ());
+ }
+
+ translated = mth;
+ }
+
private:
ASTLowerImplItem () : translated (nullptr) {}
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index 8f0c206..d4af3c2 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -2177,9 +2177,9 @@ public:
void iterate_params (std::function<bool (Expr *)> cb)
{
- for (auto it = params.begin (); it != params.end (); it++)
+ for (auto &param : params)
{
- if (!cb (it->get ()))
+ if (!cb (param.get ()))
return;
}
}
@@ -2261,6 +2261,27 @@ public:
void accept_vis (HIRVisitor &vis) override;
+ std::unique_ptr<Expr> &get_receiver () { return receiver; }
+
+ PathExprSegment get_method_name () const { return method_name; };
+
+ std::vector<std::unique_ptr<Expr> > &get_params () { return params; }
+ const std::vector<std::unique_ptr<Expr> > &get_params () const
+ {
+ return params;
+ }
+
+ size_t num_params () const { return params.size (); }
+
+ void iterate_params (std::function<bool (Expr *)> cb)
+ {
+ for (auto &param : params)
+ {
+ if (!cb (param.get ()))
+ return;
+ }
+ }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/hir/tree/rust-hir-full-test.cc b/gcc/rust/hir/tree/rust-hir-full-test.cc
index 8502c9c..e4fa39a 100644
--- a/gcc/rust/hir/tree/rust-hir-full-test.cc
+++ b/gcc/rust/hir/tree/rust-hir-full-test.cc
@@ -676,7 +676,7 @@ Method::as_string () const
}
str += "\n Block expr (body): \n ";
- str += expr->as_string ();
+ str += function_body->as_string ();
return str;
}
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index e90dbb4..4ab23e1 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -297,10 +297,13 @@ private:
Location locus;
+ Analysis::NodeMapping mappings;
+
// Unrestricted constructor used for error state
- SelfParam (Lifetime lifetime, bool has_ref, bool is_mut, Type *type)
+ SelfParam (Analysis::NodeMapping mappings, Lifetime lifetime, bool has_ref,
+ bool is_mut, Type *type)
: has_ref (has_ref), is_mut (is_mut), lifetime (std::move (lifetime)),
- type (type)
+ type (type), mappings (mappings)
{}
// this is ok as no outside classes can ever call this
@@ -319,21 +322,23 @@ public:
}
// Type-based self parameter (not ref, no lifetime)
- SelfParam (std::unique_ptr<Type> type, bool is_mut, Location locus)
+ SelfParam (Analysis::NodeMapping mappings, std::unique_ptr<Type> type,
+ bool is_mut, Location locus)
: has_ref (false), is_mut (is_mut), lifetime (Lifetime::error ()),
- type (std::move (type)), locus (locus)
+ type (std::move (type)), locus (locus), mappings (mappings)
{}
// Lifetime-based self parameter (is ref, no type)
- SelfParam (Lifetime lifetime, bool is_mut, Location locus)
+ SelfParam (Analysis::NodeMapping mappings, Lifetime lifetime, bool is_mut,
+ Location locus)
: has_ref (true), is_mut (is_mut), lifetime (std::move (lifetime)),
- locus (locus)
+ locus (locus), mappings (mappings)
{}
// Copy constructor requires clone
SelfParam (SelfParam const &other)
: has_ref (other.has_ref), is_mut (other.is_mut), lifetime (other.lifetime),
- locus (other.locus)
+ locus (other.locus), mappings (other.mappings)
{
if (other.type != nullptr)
type = other.type->clone_type ();
@@ -348,6 +353,7 @@ public:
has_ref = other.has_ref;
lifetime = other.lifetime;
locus = other.locus;
+ mappings = other.mappings;
return *this;
}
@@ -359,6 +365,18 @@ public:
std::string as_string () const;
Location get_locus () const { return locus; }
+
+ bool get_has_ref () const { return has_ref; };
+ bool get_is_mut () const { return is_mut; }
+
+ // TODO: is this better? Or is a "vis_block" better?
+ std::unique_ptr<Type> &get_type ()
+ {
+ rust_assert (has_type ());
+ return type;
+ }
+
+ Analysis::NodeMapping get_mappings () { return mappings; }
};
// Qualifiers for function, i.e. const, unsafe, extern etc.
@@ -542,6 +560,8 @@ protected:
// A method (function belonging to a type)
class Method : public InherentImplItem, public TraitImplItem
{
+ Analysis::NodeMapping mappings;
+
// moved from impl items for consistency
std::vector<Attribute> outer_attrs;
Visibility vis;
@@ -566,9 +586,7 @@ class Method : public InherentImplItem, public TraitImplItem
// bool has_where_clause;
WhereClause where_clause;
- std::unique_ptr<BlockExpr> expr;
-
- Analysis::NodeMapping mappings;
+ std::unique_ptr<BlockExpr> function_body;
Location locus;
@@ -603,8 +621,8 @@ public:
self_param (std::move (self_param)),
function_params (std::move (function_params)),
return_type (std::move (return_type)),
- where_clause (std::move (where_clause)), expr (std::move (function_body)),
- locus (locus)
+ where_clause (std::move (where_clause)),
+ function_body (std::move (function_body)), locus (locus)
{}
// TODO: add constructor with less fields
@@ -616,7 +634,8 @@ public:
method_name (other.method_name), self_param (other.self_param),
function_params (other.function_params),
return_type (other.return_type->clone_type ()),
- where_clause (other.where_clause), expr (other.expr->clone_block_expr ()),
+ where_clause (other.where_clause),
+ function_body (other.function_body->clone_block_expr ()),
locus (other.locus)
{
generic_params.reserve (other.generic_params.size ());
@@ -636,7 +655,7 @@ public:
function_params = other.function_params;
return_type = other.return_type->clone_type ();
where_clause = other.where_clause;
- expr = other.expr->clone_block_expr ();
+ function_body = other.function_body->clone_block_expr ();
locus = other.locus;
generic_params.reserve (other.generic_params.size ());
@@ -661,6 +680,58 @@ public:
return get_mappings ();
};
+ // Returns whether function has return type - if not, it is void.
+ bool has_function_return_type () const { return return_type != nullptr; }
+
+ std::vector<FunctionParam> &get_function_params () { return function_params; }
+ const std::vector<FunctionParam> &get_function_params () const
+ {
+ return function_params;
+ }
+
+ std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
+ {
+ return generic_params;
+ }
+ const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const
+ {
+ return generic_params;
+ }
+
+ // TODO: is this better? Or is a "vis_block" better?
+ std::unique_ptr<BlockExpr> &get_definition ()
+ {
+ rust_assert (function_body != nullptr);
+ return function_body;
+ }
+
+ SelfParam &get_self_param () { return self_param; }
+ const SelfParam &get_self_param () const { return self_param; }
+
+ // TODO: is this better? Or is a "vis_block" better?
+ std::unique_ptr<Type> &get_return_type ()
+ {
+ rust_assert (has_return_type ());
+ return return_type;
+ }
+
+ // TODO: is this better? Or is a "vis_block" better?
+ WhereClause &get_where_clause ()
+ {
+ rust_assert (has_where_clause ());
+ return where_clause;
+ }
+
+ Identifier get_method_name () const { return method_name; }
+
+ Location get_locus () const { return locus; }
+
+ std::unique_ptr<BlockExpr> &get_function_body () { return function_body; }
+ const std::unique_ptr<BlockExpr> &get_function_body () const
+ {
+ return function_body;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h
index 1bba506..9a772f0 100644
--- a/gcc/rust/hir/tree/rust-hir-path.h
+++ b/gcc/rust/hir/tree/rust-hir-path.h
@@ -228,6 +228,8 @@ public:
std::string as_string () const;
Location get_locus () const { return locus; }
+
+ PathIdentSegment get_segment () const { return segment_name; }
};
// HIR node representing a pattern that involves a "path" - abstract base class
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index f62f17c..d563f93 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -91,6 +91,15 @@ public:
});
}
+ void visit (AST::MethodCallExpr &expr)
+ {
+ ResolveExpr::go (expr.get_receiver_expr ().get (), expr.get_node_id ());
+ expr.iterate_params ([&] (AST::Expr *p) mutable -> bool {
+ ResolveExpr::go (p, expr.get_node_id ());
+ return true;
+ });
+ }
+
void visit (AST::AssignmentExpr &expr)
{
ResolveExpr::go (expr.get_left_expr ().get (), expr.get_node_id ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 5ed98a9..8b6227e 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -129,6 +129,58 @@ public:
resolver->get_type_scope ().peek ()->clear_name ("Self", resolved_node);
}
+ void visit (AST::Method &method)
+ {
+ if (method.has_return_type ())
+ ResolveType::go (method.get_return_type ().get (), method.get_node_id ());
+
+ NodeId scope_node_id = method.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+ // self turns into self: Self as a function param
+ AST::SelfParam &self_param = method.get_self_param ();
+ AST::IdentifierPattern self_pattern (
+ self_param.get_node_id (), "self", self_param.get_locus (),
+ self_param.get_has_ref (), self_param.get_is_mut (),
+ std::unique_ptr<AST::Pattern> (nullptr));
+
+ std::vector<std::unique_ptr<AST::TypePathSegment> > segments;
+ segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+ new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+
+ AST::TypePath self_type_path (std::move (segments),
+ self_param.get_locus ());
+
+ ResolveType::go (&self_type_path, self_param.get_node_id ());
+ PatternDeclaration::go (&self_pattern, self_param.get_node_id ());
+
+ resolver->mark_assignment_to_decl (self_pattern.get_node_id (),
+ self_pattern.get_node_id ());
+
+ // we make a new scope so the names of parameters are resolved and shadowed
+ // correctly
+ for (auto &param : method.get_function_params ())
+ {
+ ResolveType::go (param.get_type ().get (), param.get_node_id ());
+ PatternDeclaration::go (param.get_pattern ().get (),
+ param.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_assignment_to_decl (param.get_pattern ()->get_node_id (),
+ param.get_node_id ());
+ }
+
+ // resolve the function body
+ ResolveExpr::go (method.get_definition ().get (), method.get_node_id ());
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ }
+
private:
ResolveItem () : ResolverBase (UNKNOWN_NODEID) {}
};
diff --git a/gcc/rust/typecheck/rust-hir-method-resolve.h b/gcc/rust/typecheck/rust-hir-method-resolve.h
new file mode 100644
index 0000000..9a6c76f
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-method-resolve.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_METHOD_RESOLVE_H
+#define RUST_HIR_METHOD_RESOLVE_H
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+class MethodResolution : public TypeCheckBase
+{
+public:
+ static std::vector<HIR::Method *> Probe (TyTy::TyBase *receiver,
+ HIR::PathExprSegment method_name)
+ {
+ MethodResolution probe (receiver, method_name);
+
+ // lookup impl items for this crate and find all methods that can resolve to
+ // this receiver
+ probe.mappings->iterate_impl_items (
+ [&] (HirId id, HIR::InherentImplItem *item) mutable -> bool {
+ item->accept_vis (probe);
+ return true;
+ });
+
+ return probe.probed;
+ }
+
+ void visit (HIR::Method &method)
+ {
+ TyTy::TyBase *self_lookup = nullptr;
+ if (!context->lookup_type (
+ method.get_self_param ().get_mappings ().get_hirid (), &self_lookup))
+ {
+ rust_error_at (method.get_self_param ().get_locus (),
+ "failed to lookup lookup self type in MethodProbe");
+ return;
+ }
+
+ // are the names the same
+ HIR::PathIdentSegment seg = method_name.get_segment ();
+ if (seg.as_string ().compare (method.get_method_name ()) != 0)
+ {
+ // if the method name does not match then this is not a valid match
+ return;
+ }
+
+ // FIXME this can be simplified with
+ // https://github.com/Rust-GCC/gccrs/issues/187
+ auto combined = receiver->combine (self_lookup);
+ if (combined == nullptr)
+ {
+ // incompatible self argument then this is not a valid method for this
+ // receiver
+ return;
+ }
+ delete combined;
+
+ probed.push_back (&method);
+ }
+
+private:
+ MethodResolution (TyTy::TyBase *receiver, HIR::PathExprSegment method_name)
+ : TypeCheckBase (), receiver (receiver), method_name (method_name)
+ {}
+
+ TyTy::TyBase *receiver;
+ HIR::PathExprSegment method_name;
+
+ std::vector<HIR::Method *> probed;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_METHOD_RESOLVE_H
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 82977e4..e6cca19 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -24,6 +24,7 @@
#include "rust-tyty.h"
#include "rust-tyty-call.h"
#include "rust-hir-type-check-struct-field.h"
+#include "rust-hir-method-resolve.h"
namespace Rust {
namespace Resolver {
@@ -37,7 +38,10 @@ public:
expr->accept_vis (resolver);
if (resolver.infered == nullptr)
- return new TyTy::ErrorType (expr->get_mappings ().get_hirid ());
+ {
+ rust_error_at (expr->get_locus_slow (), "failed to resolve expression");
+ return new TyTy::ErrorType (expr->get_mappings ().get_hirid ());
+ }
auto ref = expr->get_mappings ().get_hirid ();
resolver.infered->set_ref (ref);
@@ -196,9 +200,8 @@ public:
TyTy::TyBase *lookup;
if (!context->lookup_type (ref, &lookup))
{
- // FIXME we need to be able to lookup the location info for the
- // reference here
- rust_error_at (expr.get_locus (), "consider giving this a type: %s",
+ rust_error_at (mappings->lookup_location (ref),
+ "failed to lookup type for CallExpr: %s",
expr.as_string ().c_str ());
return;
}
@@ -213,6 +216,65 @@ public:
infered->set_ref (expr.get_mappings ().get_hirid ());
}
+ void visit (HIR::MethodCallExpr &expr)
+ {
+ auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ());
+ if (receiver_tyty == nullptr)
+ {
+ rust_error_at (expr.get_receiver ()->get_locus_slow (),
+ "failed to resolve receiver in MethodCallExpr");
+ return;
+ }
+
+ // https://doc.rust-lang.org/reference/expressions/method-call-expr.html
+ // method resolution is complex in rust once we start handling generics and
+ // traits. For now we only support looking up the valid name in impl blocks
+ // which is simple. There will need to be adjustments to ensure we can turn
+ // the receiver into borrowed references etc
+
+ auto probes
+ = MethodResolution::Probe (receiver_tyty, expr.get_method_name ());
+ if (probes.size () == 0)
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to resolve the PathExprSegment to any Method");
+ return;
+ }
+ else if (probes.size () > 1)
+ {
+ rust_error_at (
+ expr.get_locus (),
+ "Generics and Traits are not implemented yet for MethodCall");
+ return;
+ }
+
+ auto resolved_method = probes.at (0);
+ TyTy::TyBase *lookup;
+ if (!context->lookup_type (resolved_method->get_mappings ().get_hirid (),
+ &lookup))
+ {
+ rust_error_at (resolved_method->get_locus (),
+ "failed to lookup type for CallExpr: %s",
+ expr.as_string ().c_str ());
+ return;
+ }
+
+ infered = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, context);
+ if (infered == nullptr)
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to lookup type to MethodCallExpr");
+ return;
+ }
+
+ infered->set_ref (expr.get_mappings ().get_hirid ());
+
+ // set up the resolved name on the path
+ resolver->insert_resolved_name (
+ expr.get_mappings ().get_nodeid (),
+ resolved_method->get_mappings ().get_nodeid ());
+ }
+
void visit (HIR::AssignmentExpr &expr)
{
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
@@ -313,7 +375,7 @@ public:
if (!context->lookup_type (ref, &lookup))
{
rust_error_at (mappings->lookup_location (ref),
- "consider giving this a type: %s",
+ "Failed to resolve IdentifierExpr type: %s",
expr.as_string ().c_str ());
return;
}
@@ -703,7 +765,7 @@ public:
if (!is_valid_type)
{
rust_error_at (expr.get_locus (),
- "expected ADT or Tuple Type got: [%s]",
+ "expected algebraic data type got: [%s]",
struct_base->as_string ().c_str ());
return;
}
@@ -747,7 +809,11 @@ public:
return;
}
- context->lookup_type (ref, &infered);
+ if (!context->lookup_type (ref, &infered))
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to resolve PathInExpression type");
+ }
}
private:
@@ -799,6 +865,7 @@ private:
&& (((TyTy::InferType *) type)->get_infer_kind ()
== TyTy::InferType::INTEGRAL));
}
+ gcc_unreachable ();
}
TyTy::TyBase *infered;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index abaee73..c8d161a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -31,9 +31,9 @@ namespace Resolver {
class TypeCheckTopLevelImplItem : public TypeCheckBase
{
public:
- static void Resolve (HIR::InherentImplItem *item)
+ static void Resolve (HIR::InherentImplItem *item, TyTy::TyBase *self)
{
- TypeCheckTopLevelImplItem resolver;
+ TypeCheckTopLevelImplItem resolver (self);
item->accept_vis (resolver);
}
@@ -81,8 +81,62 @@ public:
context->insert_type (function.get_mappings (), fnType);
}
+ void visit (HIR::Method &method)
+ {
+ TyTy::TyBase *ret_type = nullptr;
+ if (!method.has_function_return_type ())
+ ret_type = new TyTy::UnitType (method.get_mappings ().get_hirid ());
+ else
+ {
+ auto resolved
+ = TypeCheckType::Resolve (method.get_return_type ().get ());
+ if (resolved == nullptr)
+ {
+ rust_error_at (method.get_locus (),
+ "failed to resolve return type");
+ return;
+ }
+
+ ret_type = resolved->clone ();
+ ret_type->set_ref (
+ method.get_return_type ()->get_mappings ().get_hirid ());
+ }
+
+ // hold all the params to the fndef
+ std::vector<std::pair<HIR::Pattern *, TyTy::TyBase *> > params;
+
+ // add the self param at the front
+ HIR::SelfParam &self_param = method.get_self_param ();
+ HIR::IdentifierPattern *self_pattern
+ = new HIR::IdentifierPattern ("self", self_param.get_locus (),
+ self_param.get_has_ref (),
+ self_param.get_is_mut (),
+ std::unique_ptr<HIR::Pattern> (nullptr));
+ context->insert_type (self_param.get_mappings (), self->clone ());
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::TyBase *> (self_pattern, self->clone ()));
+
+ for (auto &param : method.get_function_params ())
+ {
+ // get the name as well required for later on
+ auto param_tyty = TypeCheckType::Resolve (param.get_type ());
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::TyBase *> (param.get_param_name (),
+ param_tyty));
+
+ context->insert_type (param.get_mappings (), param_tyty);
+ }
+
+ auto fnType = new TyTy::FnType (method.get_mappings ().get_hirid (), params,
+ ret_type);
+ context->insert_type (method.get_mappings (), fnType);
+ }
+
private:
- TypeCheckTopLevelImplItem () : TypeCheckBase () {}
+ TypeCheckTopLevelImplItem (TyTy::TyBase *self) : TypeCheckBase (), self (self)
+ {}
+
+ TyTy::TyBase *self;
};
class TypeCheckImplItem : public TypeCheckBase
@@ -99,7 +153,7 @@ public:
TyTy::TyBase *lookup;
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
{
- rust_error_at (function.locus, "failed to lookup function type");
+ rust_error_at (function.get_locus (), "failed to lookup function type");
return;
}
@@ -137,6 +191,49 @@ public:
context->pop_return_type ();
}
+ void visit (HIR::Method &method)
+ {
+ TyTy::TyBase *lookup;
+ if (!context->lookup_type (method.get_mappings ().get_hirid (), &lookup))
+ {
+ rust_error_at (method.get_locus (), "failed to lookup function type");
+ return;
+ }
+
+ if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
+ {
+ rust_error_at (method.get_locus (),
+ "found invalid type for function [%s]",
+ lookup->as_string ().c_str ());
+ return;
+ }
+
+ // need to get the return type from this
+ TyTy::FnType *resolve_fn_type = (TyTy::FnType *) lookup;
+ auto expected_ret_tyty = resolve_fn_type->return_type ();
+ context->push_return_type (expected_ret_tyty);
+
+ TypeCheckExpr::Resolve (method.get_function_body ().get ());
+ if (method.get_function_body ()->has_expr ())
+ {
+ auto resolved
+ = TypeCheckExpr::Resolve (method.get_function_body ()->expr.get ());
+
+ auto ret_resolved = expected_ret_tyty->combine (resolved);
+ if (ret_resolved == nullptr)
+ {
+ rust_error_at (method.get_function_body ()->expr->get_locus_slow (),
+ "failed to resolve final expression");
+ return;
+ }
+
+ context->peek_return_type ()->append_reference (
+ ret_resolved->get_ref ());
+ }
+
+ context->pop_return_type ();
+ }
+
private:
TypeCheckImplItem (TyTy::TyBase *self) : TypeCheckBase (), self (self) {}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
index 46b3b0f..61823bf 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
@@ -137,11 +137,15 @@ public:
void visit (HIR::InherentImpl &impl_block)
{
- TypeCheckType::Resolve (impl_block.get_type ().get ());
- for (auto &impl_item : impl_block.get_impl_items ())
+ auto self = TypeCheckType::Resolve (impl_block.get_type ().get ());
+ if (self == nullptr)
{
- TypeCheckTopLevelImplItem::Resolve (impl_item.get ());
+ rust_error_at (impl_block.get_locus (), "failed to resolve impl type");
+ return;
}
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ TypeCheckTopLevelImplItem::Resolve (impl_item.get (), self);
}
private:
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
index 0d8fffc..2f872a6 100644
--- a/gcc/rust/typecheck/rust-tycheck-dump.h
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -73,6 +73,18 @@ public:
dump += indent () + "}\n";
}
+ void visit (HIR::Method &method)
+ {
+ dump += indent () + "fn " + method.get_method_name () + " "
+ + type_string (method.get_mappings ()) + "\n";
+ dump += indent () + "{\n";
+
+ HIR::BlockExpr *function_body = method.get_function_body ().get ();
+ function_body->accept_vis (*this);
+
+ dump += indent () + "}\n";
+ }
+
void visit (HIR::BlockExpr &expr)
{
indentation_level++;
diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h
index 2b3cfb6..82b070f 100644
--- a/gcc/rust/typecheck/rust-tyty-call.h
+++ b/gcc/rust/typecheck/rust-tyty-call.h
@@ -38,7 +38,6 @@ public:
ref->accept_vis (checker);
return checker.resolved;
}
- ~TypeCheckCallExpr () {}
void visit (UnitType &type) override { gcc_unreachable (); }
void visit (InferType &type) override { gcc_unreachable (); }
@@ -71,6 +70,47 @@ private:
Analysis::Mappings *mappings;
};
+class TypeCheckMethodCallExpr : private TyVisitor
+{
+public:
+ static TyBase *go (TyBase *ref, HIR::MethodCallExpr &call,
+ Resolver::TypeCheckContext *context)
+ {
+ TypeCheckMethodCallExpr checker (call, context);
+ ref->accept_vis (checker);
+ return checker.resolved;
+ }
+
+ void visit (UnitType &type) override { gcc_unreachable (); }
+ void visit (InferType &type) override { gcc_unreachable (); }
+ void visit (TupleType &type) override { gcc_unreachable (); }
+ void visit (StructFieldType &type) override { gcc_unreachable (); }
+ void visit (ArrayType &type) override { gcc_unreachable (); }
+ void visit (BoolType &type) override { gcc_unreachable (); }
+ void visit (IntType &type) override { gcc_unreachable (); }
+ void visit (UintType &type) override { gcc_unreachable (); }
+ void visit (FloatType &type) override { gcc_unreachable (); }
+ void visit (USizeType &type) override { gcc_unreachable (); }
+ void visit (ISizeType &type) override { gcc_unreachable (); }
+ void visit (ErrorType &type) override { gcc_unreachable (); }
+ void visit (ADTType &type) override { gcc_unreachable (); };
+
+ // call fns
+ void visit (FnType &type) override;
+
+private:
+ TypeCheckMethodCallExpr (HIR::MethodCallExpr &c,
+ Resolver::TypeCheckContext *context)
+ : resolved (nullptr), call (c), context (context),
+ mappings (Analysis::Mappings::get ())
+ {}
+
+ TyBase *resolved;
+ HIR::MethodCallExpr &call;
+ Resolver::TypeCheckContext *context;
+ Analysis::Mappings *mappings;
+};
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index d506415..8b04209 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -147,14 +147,15 @@ ADTType::accept_vis (TyVisitor &vis)
std::string
ADTType::as_string () const
{
- if (num_fields () == 0)
- return identifier;
+ // if (num_fields () == 0)
+ // return identifier;
- std::string fields_buffer;
- for (auto &field : fields)
- fields_buffer += field->as_string () + ", ";
+ // std::string fields_buffer;
+ // for (auto &field : fields)
+ // fields_buffer += field->as_string () + ", ";
- return identifier + "{" + fields_buffer + "}";
+ // return identifier + "{" + fields_buffer + "}";
+ return identifier;
}
TyBase *
@@ -574,5 +575,56 @@ TypeCheckCallExpr::visit (FnType &type)
resolved = type.get_return_type ()->clone ();
}
+// method call checker
+
+void
+TypeCheckMethodCallExpr::visit (FnType &type)
+{
+ // +1 for the receiver self
+ size_t num_args_to_call = call.num_params () + 1;
+ if (num_args_to_call != type.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ call.num_params (), type.num_params ());
+ return;
+ }
+
+ size_t i = 1;
+ call.iterate_params ([&] (HIR::Expr *param) mutable -> bool {
+ auto fnparam = type.param_at (i);
+ auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (param);
+ if (argument_expr_tyty == nullptr)
+ {
+ rust_error_at (param->get_locus_slow (),
+ "failed to resolve type for argument expr in CallExpr");
+ return false;
+ }
+
+ auto resolved_argument_type = fnparam.second->combine (argument_expr_tyty);
+ if (resolved_argument_type == nullptr)
+ {
+ rust_error_at (param->get_locus_slow (),
+ "Type Resolution failure on parameter");
+ return false;
+ }
+
+ context->insert_type (param->get_mappings (), resolved_argument_type);
+
+ i++;
+ return true;
+ });
+
+ if (i != num_args_to_call)
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu", i,
+ call.num_params ());
+ return;
+ }
+
+ resolved = type.get_return_type ()->clone ();
+}
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index eb55581..8a15631 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -375,6 +375,30 @@ Mappings::lookup_hir_param (CrateNum crateNum, HirId id)
}
void
+Mappings::insert_hir_self_param (CrateNum crateNum, HirId id,
+ HIR::SelfParam *param)
+{
+ rust_assert (lookup_hir_stmt (crateNum, id) == nullptr);
+
+ hirSelfParamMappings[crateNum][id] = param;
+ nodeIdToHirMappings[crateNum][param->get_mappings ().get_nodeid ()] = id;
+}
+
+HIR::SelfParam *
+Mappings::lookup_hir_self_param (CrateNum crateNum, HirId id)
+{
+ auto it = hirSelfParamMappings.find (crateNum);
+ if (it == hirSelfParamMappings.end ())
+ return nullptr;
+
+ auto iy = it->second.find (id);
+ if (iy == it->second.end ())
+ return nullptr;
+
+ return iy->second;
+}
+
+void
Mappings::insert_hir_struct_field (CrateNum crateNum, HirId id,
HIR::StructExprField *field)
{
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index f81cee6..0d625f6 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -125,6 +125,10 @@ public:
void insert_hir_param (CrateNum crateNum, HirId id, HIR::FunctionParam *type);
HIR::FunctionParam *lookup_hir_param (CrateNum crateNum, HirId id);
+ void insert_hir_self_param (CrateNum crateNum, HirId id,
+ HIR::SelfParam *type);
+ HIR::SelfParam *lookup_hir_self_param (CrateNum crateNum, HirId id);
+
void insert_hir_struct_field (CrateNum crateNum, HirId id,
HIR::StructExprField *type);
HIR::StructExprField *lookup_hir_struct_field (CrateNum crateNum, HirId id);
@@ -152,6 +156,20 @@ public:
return hirNodesWithinCrate[crate];
}
+ void
+ iterate_impl_items (std::function<bool (HirId, HIR::InherentImplItem *)> cb)
+ {
+ for (auto it = hirImplItemMappings.begin ();
+ it != hirImplItemMappings.end (); it++)
+ {
+ for (auto iy = it->second.begin (); iy != it->second.end (); iy++)
+ {
+ if (!cb (iy->first, iy->second))
+ return;
+ }
+ }
+ }
+
private:
Mappings ();
@@ -176,6 +194,7 @@ private:
hirStructFieldMappings;
std::map<CrateNum, std::map<HirId, HIR::InherentImplItem *> >
hirImplItemMappings;
+ std::map<CrateNum, std::map<HirId, HIR::SelfParam *> > hirSelfParamMappings;
// location info
std::map<CrateNum, std::map<NodeId, Location> > locations;
diff --git a/gcc/testsuite/rust.test/compilable/methods1.rs b/gcc/testsuite/rust.test/compilable/methods1.rs
new file mode 100644
index 0000000..cffa02e
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/methods1.rs
@@ -0,0 +1,39 @@
+struct Point {
+ x: f64,
+ y: f64,
+}
+
+impl Point {
+ fn origin() -> Point {
+ Point { x: 0.0, y: 0.0 }
+ }
+
+ fn new(x: f64, y: f64) -> Point {
+ Point { x: x, y: y }
+ }
+}
+
+struct Rectangle {
+ p1: Point,
+ p2: Point,
+}
+
+impl Rectangle {
+ fn from(p1: Point, p2: Point) -> Self {
+ Self { p1, p2 }
+ }
+
+ fn sum_x(self) -> f64 {
+ let p1 = self.p1;
+ let p2 = self.p2;
+ p1.x + p2.x
+ }
+}
+
+fn main() {
+ let p1 = Point::origin();
+ let p2 = Point::new(3.0, 4.0);
+ let rect = Rectangle::from(p1, p2);
+
+ let sum = rect.sum_x();
+}
diff --git a/gcc/testsuite/rust.test/compilable/methods2.rs b/gcc/testsuite/rust.test/compilable/methods2.rs
new file mode 100644
index 0000000..96a3211
--- /dev/null
+++ b/gcc/testsuite/rust.test/compilable/methods2.rs
@@ -0,0 +1,41 @@
+struct Point {
+ x: f64,
+ y: f64,
+}
+
+impl Point {
+ fn origin() -> Point {
+ Point { x: 0.0, y: 0.0 }
+ }
+
+ fn new(x: f64, y: f64) -> Point {
+ Point { x: x, y: y }
+ }
+}
+
+struct Rectangle {
+ p1: Point,
+ p2: Point,
+}
+
+impl Rectangle {
+ fn from(p1: Point, p2: Point) -> Self {
+ Self { p1, p2 }
+ }
+}
+
+fn main() {
+ let p1 = Point::origin();
+ let p2 = Point::new(3.0, 4.0);
+ let rect = Rectangle::from(p1, p2);
+
+ let sum = rect.sum_x();
+}
+
+impl Rectangle {
+ fn sum_x(self) -> f64 {
+ let p1 = self.p1;
+ let p2 = self.p2;
+ p1.x + p2.x
+ }
+}