nitlang / nit

Nit language
http://nitlanguage.org
Apache License 2.0
239 stars 65 forks source link

Global compiler: unreachable code warning when using nullable in generic types #2780

Open Louis-Vincent opened 5 years ago

Louis-Vincent commented 5 years ago

Here's the use case when compiling with --global:

class C[E]
        var x: E
        redef fun to_s
        do
                if x != null then
                        return "x is {x.as(not null)}"
                end
                return "x is null"
        end
end
var c1 = new C[nullable Object](null)
var c2 = new C[nullable Int](null)
c1.x = "test"
c2.x = 100

The global compiler will try to inline the message sending when c1.x = .... However, this produce type_test which is unreachable :

$ nitc failing_example.nit --global
nitc__temp.nitgg.1.c: In function ‘nitc__temp___core__Sys___main’:
nitc__temp.nitgg.1.c:7419:6: warning: statement will never be executed [-Wswitch-unreachable]
 var2 = 1;
 ~~~~~^~~
nitc__temp.nitgg.1.c:7474:6: warning: statement will never be executed [-Wswitch-unreachable]
 var7 = 1;
 ~~~~~^~~
nitc__temp.nitgg.1.c:7577:7: warning: statement will never be executed [-Wswitch-unreachable]
 var23 = 1;

The generated C code :

switch(var->classid) {
                default: /* test C[nullable Object] */
                        { /* Inline temp$C$x= (var,((val*)NULL)) */
                                /* Covariant cast for argument 0 (x) <((val*)NULL):null> isa E */
                                /* isa nullable Object on <((val*)NULL):null> */
                                if (((val*)NULL) == NULL) {
                                        var2 = 1; /* isa nullable Object */
                                } else 
                                        switch(((val*)NULL)->classid) {
                                                var2 = 1;
                                                break;
                                                default:
                                                var2 = 0;
                                        }
                                if (unlikely(!var2)) {
                                        {
                                                struct catch_stack_t *catchStack = getCatchStack();
                                                if(catchStack->cursor >= 0){
                                                        longjmp(catchStack->envs[catchStack->cursor], 1);
                                                }
                                        }
                                        var_class_name = class_names[((val*)NULL)->classid];
                                        PRINT_ERROR("Runtime error: Cast failed. Expected `%s`, got `%s`", "E", var_class_name);
                                        PRINT_ERROR(" (%s:%d)\n", FILE_nitc__temp, 2);
                                        fatal_exit(1);
                                }
                                /* write _x on <var:C[nullable Object] exact> */
                                switch(var->classid) {
                                        default: /*ID_nitc__C__nullable__core__Object*/
                                                ((struct nitc__C__nullable__core__Object*)var)->nitc___nitc__C____x = ((val*)NULL);
                                                break;
                                }
RET_LABEL1:(void)0;
                        }
                        break;
        }