crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.33k stars 1.61k forks source link

Bug: `main` function conflicts with `main` fun #4761

Open tzekid opened 7 years ago

tzekid commented 7 years ago

I tried out an old project and got a rather strange error.
The project is bindgencr. Unfortunately I don't really know what the root cause of the bug / error is, but (at least on my system) it can be easily reproduced by downloading the rep. and running the sample code.

Here's an example:

λ crystal run src/bindgencr.cr -- -l cimgui -n LibCimgui samples/cimgui/cimgui.xml 
Error in src/bindgencr.cr:1: while requiring "prelude"

require "./bindgencr/*"
^

in /usr/lib/crystal/prelude.cr:48: while requiring "main": BUG: called Pointer(Pointer(UInt8)).restriction_of?(Array(String))

require "main"
^

I've tried running it with the --prelude=empty flag, but that gives out the same output as before.

My setup info:

λ uname -s -r
Linux 4.12.3-1-MANJARO
λ crystal -v
Crystal 0.23.1 (2017-07-17) LLVM 4.0.1
wmoxam commented 7 years ago

To reproduce:

def main(options, arguments : Array(String))
end

main("foo", ["bar", "baz"])

https://play.crystal-lang.org/#/r/2ghq

straight-shoota commented 7 years ago

Looks like your def main collides with fun main which is probably the only fun outside a lib - and ofc also defined in the empty prelude.

A minimal sample to reproduce doesn't even to call main itself:

def main(options, arguments : Array(String))
end

https://play.crystal-lang.org/#/r/2gi8

RX14 commented 7 years ago

At the very least we should have a nicer error message for this.

straight-shoota commented 7 years ago

Yes, the parser could prevent to define a method named main as a special case. Or, better find a way around this. From inside a Crystal program you'll never need to call the main function so this could perhaps be fixed with proper scoping or - as a naive approach - transparently renaming main method and calls.

miketheman commented 5 years ago

codetriage There's still some bugginess around this in 0.26.1

Error in line 1: while requiring "prelude"

in /usr/lib/crystal/prelude.cr:39: while requiring "crystal/main": BUG: called Pointer(Pointer(UInt8)).restriction_of?(Array(String))

require "crystal/main"
^

https://play.crystal-lang.org/#/r/58n0

asterite commented 4 years ago

I think we need to use a different name for main, maybe __main, or even __crystal_main. Then the compiler could look up that name to define the C main function, but allowing users to define main methods without conflict.

RX14 commented 4 years ago

fun main is already defined in the prelude, we should just disallow a def with the same name.

The compiler shouldn't assume the main method name, it already pregenerates __crystal_main. Having fun main be defined in crystal makes a bunch of usecases possible, such as using SDL.

asterite commented 4 years ago

Yes. What I'm saying is, there's no need to use main for the C function. It's more common to define a main top level method. Or, put another way, no other language prevents you from using main (or any other non keyword name) as a name.

RX14 commented 4 years ago

If you want to change the symbol mangling so that fun and top-level-def with the same name don't collide I'm fine with that. Changing around how fun main works right now I'm not so sure...

jhass commented 4 years ago

I actually see no problem with not being able to define fun main to redefine main, that's what we have redefine_main for, no?

asterite commented 4 years ago

I was thinking that maybe top-level fun could be implicitly added to LibC, and only called by doing LibC.whatever. That way fun main (or any other fun, for that matter) would never conflict with a main method.

bew commented 4 years ago

I like the idea of another namespace for toplevel funs, but not with adding them to LibC, since the manually defined functions are usually not related to libc. Maybe something more like ExternalFunctions.

Note: A "long" module name is not a problem I think, because those functions are usually not called by crystal code (or very occasionally).

RX14 commented 4 years ago

I actually see no problem with not being able to define fun main to redefine main, that's what we have redefine_main for, no?

We removed redefine_main in favour of this commit: https://github.com/crystal-lang/crystal/commit/5f0fe1c09a93a8b5f53f3cb8db99af2f03644096

I like that as-is.

Sija commented 4 years ago

I like that as-is.

@RX14 As-is generates the error linked above in https://github.com/crystal-lang/crystal/issues/4761#issuecomment-429661099

RX14 commented 4 years ago

Yes. The error should be improved. But I don't think the ability to define a top-level def main (this has been complained about once in the 2.5 years since that commit) is worth changing it around.

straight-shoota commented 3 years ago

I think the easiest solution is to disallow overriding fun with def and vice versa.

We can consider some options to disambiguate with mangling as a next step. But I don't really see too many good reasons for that.