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

Widening of types of local variables and attaching macros to types are incompatible with each other. #423

Open
felixvf opened this issue Feb 17, 2016 · 2 comments

Comments

@felixvf
Copy link
Contributor

felixvf commented Feb 17, 2016

Mirah has 2 distinct features:

  1. Strong type inference with support for widening the types of local variables
  2. Macros attachable to types

Unfortunately, they are incompatible with each other.

Consider this MIrah code:

class Superclass
    macro def foo
        quote do
            puts "Superclass"
            Subclass.new
        end
    end
end

class Subclass < Superclass
    macro def foo
        quote do
            puts "Subclass"
            Superclass.new
        end
    end
end

class Test
    def run
        a = Subclass.new
        b = 0
        while b < 2
            a = a.foo
            a = a.foo
            a = a.foo
            b+=1
        end
    end
end

Test.new.run

What is the expected output of this code?

It could be

Subclass
Superclass
Subclass
Superclass
Subclass
Superclass

because the calls to method foo alternate.

It could also be

Superclass
Superclass
Superclass
Superclass
Superclass
Superclass

because the typer infers that the type of variable a (not the type of the object variable a refers to) is Superclass, because after the second invocation, it is clear that it cannot be Subclass, else the Superclass result could not be stored in the variable.

Unfortunately, the current mirah compiler does not produce either of these results.

I'd like you (@headius, @baroquebobcat, @uujava, and everyone else) to suggest what should be the correct output, and it would be nice if you could explain why.

In my opinion, when forced to decide whether to give up widening of types of local variables or to give up attaching macros to types, I would give up widening of types of local variables. Hence, the code above would be invalid, but

class Test
    def run
        a = Superclass(Subclass.new) # cast to make the type of a clear right from the outset
        b = 0
        while b < 2
            a = a.foo
            a = a.foo
            a = a.foo
            b+=1
        end
    end
end

would be valid.

This decision would also allow to remove the speculative type guessing at

# Try committing the type
which may considerably speed up the compilation time. This in turn would allow the type inference to behave monotonously (instead of the current non-monotonous behavior, where the inferred type can be changed after it has been consumed). This in turn would allow to solve #421 by invoking a macro only when type it is attached to has been determined definitely. This in turn would allow to solve #420 by supplying an argument to a macro only once that argument's type has been determined definitely, and using that argument directly instead of a ProxyNode.

@ribrdb
Copy link
Contributor

ribrdb commented Feb 25, 2016

I would think the correct output should be
Superclass
Superclass
Superclass
Superclass
Superclass
Superclass

I'm guessing it's actually:
Subclass
Superclass
Superclass
Superclass
Superclass
Superclass

Removing widening entirely seems like a pretty significant change.

@baroquebobcat
Copy link
Member

This is a tricky edge case.
Removing widening would have a lot of far reaching implications because it will dramatically increase the number of required type annotations. I would really prefer not to do that.

How about this:
If a variable being widened would change the lookup result for a macro that had been called on it, raise an error asking for type clarification.

That would make your first example invalid, but would allow for cases where the macro calls widen a type benignly. It would also not require backtracking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants