Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for module #509

Merged
merged 8 commits into from
Aug 19, 2021
Merged

Initial support for module #509

merged 8 commits into from
Aug 19, 2021

Conversation

dkm
Copy link
Member

@dkm dkm commented Jun 19, 2021

Adds name resolution, HIR lowering and type checking. For modules
which should allow for initial multiple file parsing support.

Fixes #432

@dkm dkm requested a review from philberty June 19, 2021 12:53
@dkm dkm marked this pull request as draft June 19, 2021 12:54
@dkm
Copy link
Member Author

dkm commented Jun 19, 2021

This is still on going.
There are several issues:

mod foomod {
    pub struct Foo {
        pub foofield: i32,
    }
}

fn main() {
    //    foomod::Foo{f:3i32}
    let t = foomod::Foo{
        foofield: 12,
    };
}

Is segfaulting and

mod foomod {
    pub fn totobob() {
    }
}
fn main() {
    foomod::totobob();
}

gives:

compile/torture/mod1.rs:12:9: error: failed to lookup function type
   12 |     pub fn totobob() {
      |         ^

Looks like even simple cases are not working, I must have broken something during a rebase. Still progressing slowly :)

@philberty
Copy link
Member

Can you share the segv? I think your really close to getting this right, It will take me a while to review this and the segv backtrace might give me some hints

@philberty
Copy link
Member

philberty commented Jun 19, 2021

Awesome work though thanks for bearing with this.

As I said in the other PR, I think you can see that the structures your working with are not that "nice" yet. So I think we should start thinking about better ways to improve the API's and interfaces in the front-end. I could really do with help in that area.

@dkm
Copy link
Member Author

dkm commented Jun 19, 2021

Sure I can share the segfault :) I'm in the process of rebasing/cleaning my working tree (hence the other small PRs).

@dkm
Copy link
Member Author

dkm commented Jun 19, 2021

Beware that I have not yet looked into it as I am more focused on the "nearly working" case.

rust1: internal compiler error: Segmentation fault
0xecee9f crash_signal
        ../../gcc/toplev.c:327
0x7fd82096dd5f ???
        ./signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0
0x9c3949 Rust::Resolver::TypeCheckExpr::visit(Rust::HIR::PathInExpression&)
        ../../gcc/rust/typecheck/rust-hir-type-check-expr.h:875
0x9bf5f5 Rust::Resolver::TypeCheckExpr::Resolve(Rust::HIR::Expr*, bool)
        ../../gcc/rust/typecheck/rust-hir-type-check-expr.h:48
0x9b9845 Rust::Resolver::TypeCheckStructExpr::visit(Rust::HIR::StructExprStructFields&)
        ../../gcc/rust/typecheck/rust-hir-type-check.cc:129
0x9c542a Rust::Resolver::TypeCheckStructExpr::Resolve(Rust::HIR::StructExprStructFields*)
        ../../gcc/rust/typecheck/rust-hir-type-check-struct-field.h:38
0x9c542a Rust::Resolver::TypeCheckExpr::visit(Rust::HIR::StructExprStructFields&)
        ../../gcc/rust/typecheck/rust-hir-type-check-expr.h:833
0x9bf5f5 Rust::Resolver::TypeCheckExpr::Resolve(Rust::HIR::Expr*, bool)
        ../../gcc/rust/typecheck/rust-hir-type-check-expr.h:48
0x9c2003 Rust::Resolver::TypeCheckStmt::visit(Rust::HIR::LetStmt&)
        ../../gcc/rust/typecheck/rust-hir-type-check-stmt.h:60
0x9b88e2 Rust::Resolver::TypeCheckStmt::Resolve(Rust::HIR::Stmt*, bool)
        ../../gcc/rust/typecheck/rust-hir-type-check-stmt.h:38
0x9b88e2 operator()
        ../../gcc/rust/typecheck/rust-hir-type-check.cc:97
0x9b88e2 __invoke_impl<bool, Rust::Resolver::TypeCheckExpr::visit(Rust::HIR::BlockExpr&)::<lambda(Rust::HIR::Stmt*)>&, Rust::HIR::Stmt*>
        /usr/include/c++/10/bits/invoke.h:60
0x9b88e2 __invoke_r<bool, Rust::Resolver::TypeCheckExpr::visit(Rust::HIR::BlockExpr&)::<lambda(Rust::HIR::Stmt*)>&, Rust::HIR::Stmt*>
        /usr/include/c++/10/bits/invoke.h:141
0x9b88e2 _M_invoke
        /usr/include/c++/10/bits/std_function.h:291
0x9b8a89 std::function<bool (Rust::HIR::Stmt*)>::operator()(Rust::HIR::Stmt*) const
        /usr/include/c++/10/bits/std_function.h:622
0x9b8a89 Rust::HIR::BlockExpr::iterate_stmts(std::function<bool (Rust::HIR::Stmt*)>)
        ../../gcc/rust/hir/tree/rust-hir-expr.h:2484
0x9b8a89 Rust::Resolver::TypeCheckExpr::visit(Rust::HIR::BlockExpr&)
        ../../gcc/rust/typecheck/rust-hir-type-check.cc:96
0x9bf5f5 Rust::Resolver::TypeCheckExpr::Resolve(Rust::HIR::Expr*, bool)
        ../../gcc/rust/typecheck/rust-hir-type-check-expr.h:48
0x9bfae5 Rust::Resolver::TypeCheckItem::visit(Rust::HIR::Function&)
        ../../gcc/rust/typecheck/rust-hir-type-check-item.h:81
0x9b904b Rust::Resolver::TypeCheckItem::Resolve(Rust::HIR::Item*)
        ../../gcc/rust/typecheck/rust-hir-type-check-item.h:40
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

mappings->get_next_localdef_id (crate_num));

// should be lowered from module.get_vis()
HIR::Visibility vis = HIR::Visibility::create_public ();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a case to make a much simpler HIR::visibility, an enum might just work: https://doc.rust-lang.org/stable/nightly-rustc/rustc_hir/hir/enum.VisibilityKind.html

void visit (AST::ModuleBodied& module) override {
auto path = prefix.append (CanonicalPath(module.get_name()));
resolver->get_name_scope ().insert (
path, module.get_node_id (), module.get_locus (), false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name resolution stuff could be extracted into a single commit a test case like:

mod foo {
  struct A;
}

fn main() {}

Might work since the path expression stuff will not be invoked.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, added in a dedicated test and checked it works with only the changes for name resolution applied.

Copy link
Member

@philberty philberty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks really good, I am going to check out your branch and try something since I think your 99% of the way there.

I think the only change needed would be to potentially extract this into 2-3 commits.

  1. name resolution
  2. HIR lowering
  3. Type resolution and finish PathExpression work + testcases

Nice job :)

@philberty
Copy link
Member

I've pushed this commit onto a branch: c361bec

you should be able to cherry-pick in and squash if you like.

It allows for the compilation of:

pub struct Bar {
    pub f: i32,
}

mod foomod {
    pub struct Foo {
        pub prout: i32,
    }

    pub fn totoprout() -> i32 {
        return 3i32;
    }
}

pub fn toto() {}

fn test() -> Bar {
    Bar { f: 23i32 }
}

fn main() {
    let a;
    a = foomod::Foo { prout: 3i32 };

    toto();

    let b;
    b = foomod::totoprout();
}

@dkm
Copy link
Member Author

dkm commented Jun 21, 2021

I think this looks really good, I am going to check out your branch and try something since I think your 99% of the way there.

I think the only change needed would be to potentially extract this into 2-3 commits.

1. name resolution

2. HIR lowering

3. Type resolution and finish PathExpression work + testcases

Nice job :)

Ok ! I'll first add few tests and if everything is fine, I'll split the changes in 3. I'll squash your changes and mark you as co-author if that's ok with you ?

@dkm
Copy link
Member Author

dkm commented Aug 3, 2021

Haven't had much time for this :/
There is still problem with name resolution.
This:

mod A {
    pub mod B {
        pub mod C {
            pub struct Foo {
            }
        }
    }
}

impl A::B::C::Foo {
    pub fn new() -> Self {
        A::B::C::Foo {
            f: 23i32,
        }
    }
}
fn main() {
    let _a = A::B::C::Foo::new();
}

raises this error:

error: failed to resolve TypePath: A::B::C::Foo

The error comes from the lookup method Scope::lookup() that iterates over Ribs but never queries the one having the name defined. I think I'm missing something to correctly route the search instead of simply going up the Rib stack.

And for other simple case like:

mod A {
    pub struct Foo {
        pub f: i32,
    }
}

fn main() {
    let _b = A::Foo {
        f: 33i32,
    };
}

GCC will ICE after getting null from resolve_root_path( "A::Foo::[C: 0 Nid: 15 Hid: 26]") in void visit (HIR::PathInExpression &expr).

@dkm dkm force-pushed the pr/mod branch 2 times, most recently from cc18e0f to 273b784 Compare August 6, 2021 08:36
lookup = prefix.append (canonical_path);

auto resolver = Resolver::get ();
NodeId resolved_node = UNKNOWN_NODEID;

// Lookup type in the following priority order:
Copy link
Member Author

@dkm dkm Aug 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here, I need to do what's documented here : https://github.com/rust-lang/rust/blob/1f94abcda6884893d4723304102089198caa0839/compiler/rustc_resolve/src/lib.rs#L1722
When the type can't be found in the type NS, then we need to look for it in modules (and others element as documented). Is my understanding correct here? Currently, I'm trying to see if this would work by doing a global search in all Ribs (instead of targeting only the ones related to the module). It seems to work, but then a similar lookup is done so I need do apply the same workaround.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting to read, I was thinking the fixup we added yesterday here:

which will do a scan toplevel with an empty path prefix a 2nd time which was causing an assertion inside insert_new_definition which was fixed with my PR earlier today should solve this.

I think I would like to see if you can revert this change to the type path name scope resolution and see if the fixes from yesterday and today still allow your test cases to pass.

Basically what happens is when the name resolver starts at the moment we endup with all the AST::Items canonical path's within the top-level scope so for example:

mod foo {
    pub struct Foo {
        pub f: i32,
    }

    pub fn foofn() -> i32 {
        return 3i32;
    }
}

struct Bar {b:i32}

The first scan toplevel gives us the paths:

[foo::Foo , foo:foofn, Bar]

But when we do the ResolveItems and we hit the Module we should do the resolve toplevel on each item then resolve item on each item so we end up with:

[Foo, foofn]
[foo::Foo , foo:foofn, Bar]

This means the relative paths of each item should be resolveable within the new rib that has been created.

The solution inside rustc here is kind of clever. The name resolver inside gccrs might need some thought because, one of the cases we don't funny support properly is the case of AST:::Items within blocks which can be forward declared and constantly having to do scan toplevel is getting a bit confusing.

Lets revert this change, see how it works and maintain a comment to the piece of source code from rustc which might provide a cleaner solution down the line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, removing the use of iterate_type_ribs does not break anything now.

}
return true;
});

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the defId is looked up only in the type NS and where it should probably use the same search behavior (ie. search in modules if not found in type NS).

@dkm dkm force-pushed the pr/mod branch 2 times, most recently from 265e4a7 to a3d7606 Compare August 9, 2021 13:33
@philberty
Copy link
Member

This was so close:

diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 923faf8b416..bc9aa4a9418 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -226,13 +226,14 @@ public:
     resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
     resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
 
-    auto path = CanonicalPath::new_seg (module.get_node_id(), module.get_name ());
+    auto path
+      = CanonicalPath::new_seg (module.get_node_id (), module.get_name ());
 
     for (auto &item : module.get_items ())
-      ResolveTopLevel::go (item.get (), path);
+      ResolveTopLevel::go (item.get ());
 
     for (auto &item : module.get_items ())
-      ResolveItem::go(item.get());
+      ResolveItem::go (item.get ());
 
     resolver->get_name_scope ().pop ();
     resolver->get_type_scope ().pop ();
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index c28a0820e52..d6ca42018e8 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -42,8 +42,8 @@ public:
 
   void visit (AST::Module &module) override
   {
-    auto path = prefix.append (CanonicalPath::new_seg (module.get_node_id(),
-                                                       module.get_name()));
+    auto path = prefix.append (
+      CanonicalPath::new_seg (module.get_node_id (), module.get_name ()));
     resolver->get_name_scope ().insert (
       path, module.get_node_id (), module.get_locus (), false,
       [&] (const CanonicalPath &, NodeId, Location locus) -> void {
@@ -53,15 +53,13 @@ public:
       });
 
     resolver->insert_new_definition (module.get_node_id (),
-                                     Definition{
-                                       module.get_node_id (),
-                                       module.get_node_id ()
-                                     });
+                                    Definition{module.get_node_id (),
+                                               module.get_node_id ()});
 
     // This crashes the compiler. Resolving top level is OK, but looks like it's
     // missing parts.
-    // for (auto &item : module.get_items())
-    //   ResolveTopLevel::go (item.get(), path);
+    for (auto &item : module.get_items ())
+      ResolveTopLevel::go (item.get (), path);
   }
 
   void visit (AST::TypeAlias &alias) override

@dkm dkm force-pushed the pr/mod branch 3 times, most recently from c0cbd69 to 1f2ce22 Compare August 13, 2021 22:01
@philberty
Copy link
Member

Nice work! The build is passing.

@dkm
Copy link
Member Author

dkm commented Aug 14, 2021

I did some cleanup in tests to remove unnecessary dups. I've also added an execution test that is currently FAIL (but must be minor).

f: -23i32,
};

a.f - b.f
Copy link
Member

@philberty philberty Aug 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it not be a.f + b.f so that we return 0? I could be wrong but looking at this it looks like this to me:

23 - (-23)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

woops

Copy link
Member

@philberty philberty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM to merge I think the commit message still references WIP.

@dkm
Copy link
Member Author

dkm commented Aug 14, 2021

LGTM to merge I think the commit message still references WIP.

Thanks for reviewing it even in draft state. Let me do a last proof reading, remove the draft state and reword first PR message :D

@dkm dkm changed the title WIP: initial work for better module support Initial support for module Aug 18, 2021
@dkm dkm marked this pull request as ready for review August 18, 2021 20:35
@dkm
Copy link
Member Author

dkm commented Aug 18, 2021

Hope to have everything in order now. All commits should still be correct and should not cause failure in buildbot.

Mark Wielaard and others added 8 commits August 18, 2021 22:59
bools and chars can be cast to any integer type, but not to floats or
each other. Adjust the BoolCastRule and CharCastRule to allow these
casts. Add a postive test "as_bool_char.rs" and negative test
"bad_as_bool_char.rs" to check the correct casts are accepted and the
illegal casts produce errors.

Resolves: Rust-GCC#629
The gcc constant folding code uses the type_for_size langhook. Use the
default implementation instead of crashing when the langhook is
called. Add a new testcase "prims_struct_eq.rs" that creates trees
that triggers the constant folding.

Also remove the write_globals langhook which was removed when early
debug was integrated into gcc.
Add module map and required methods to access it.

refs Rust-GCC#432
Allow for getting a module's name.

ref Rust-GCC#432
Implement required visitor methods for resolving names in modules.

ref Rust-GCC#432

Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Lower AST::Module to HIR::ModuleBodied.
Add HIR::ModuleBodied::get_items to access module's items.

Fix tests that are already using module.

ref Rust-GCC#432
Typechecking and backend for Modules.

ref Rust-GCC#432

Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Add tests for Module support.

ref Rust-GCC#432
@philberty
Copy link
Member

bors r+

@bors
Copy link
Contributor

bors bot commented Aug 19, 2021

Build succeeded:

@bors bors bot merged commit 387f736 into Rust-GCC:master Aug 19, 2021
@dkm dkm deleted the pr/mod branch September 1, 2021 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mod keyword not supported.
2 participants