JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.88k stars 5.49k forks source link

Strange variable scoping error involving modules #18313

Open turtleslow opened 8 years ago

turtleslow commented 8 years ago

Running the following in a fresh session:

using Gadfly

type MyTypeA
    value::Float64
    MyTypeA(v) = new(v)
end

type MyTypeB
    value::Float64
    MyTypeB(v::Float64) = new(v)
end

if true #no error if conditional is removed
    px = 100.0

    a  = MyTypeA(px)

    println("The value of a.value is $(a.value) with type $(typeof(a.value))")
    println("The value of px is $px with type $(typeof(px))")

    b  = MyTypeB(px)
    println("The value of b.value is $(b.value) with type $(typeof(b.value))")

    for ii=1:1 #no error if loop is removed
    end
end

returns:

WARNING: imported binding for px overwritten in module Main
The value of a.value is 100.0 with type Float64
The value of px is 100.0 with type Float64
ERROR: MethodError: `convert` has no method matching convert(::Type{MyTypeB}, ::Float64)
This may have arisen from a call to the constructor MyTypeB(...),
since type constructors fall back to convert methods.
Closest candidates are:
  MyTypeB(::Float64)
  call{T}(::Type{T}, ::Any)
  convert{T}(::Type{T}, ::T)
 [inlined code] from none:9
 in anonymous at no file:0

Note that I must have the following to create this error: 1) It must be a new Julia session 2 )The if statement must be there 3) The for loop must be there

My versioninfo() is:

Julia Version 0.4.6
Commit 2e358ce* (2016-06-19 17:16 UTC)
Platform Info:
  System: Linux (x86_64-suse-linux)
  CPU: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
  WORD_SIZE: 64
  BLAS: liblapack.so.3
  LAPACK: liblapack
  LIBM: libopenlibm
  LLVM: libLLVM-3.3

The code does not throw an error on jupyter (v 3.2). I understand Gadfly.px has type Measures.Length{:mm,Float64}, but I have not been able to replicate this without using Gadfly in trying to narrow down the cause of the issue.

yuyichao commented 8 years ago

This is essentially #265

yuyichao commented 8 years ago

Reduced code is

module A
export px
const px = ""
end
using A

type B
    value::Float64
    B(v::Float64) = new(v)
end

begin
    px = 1.0

    println(px, ", ", typeof(px))

    b = B(px)

    for ii=1:1 #no error if loop is removed
    end
end

The dummy loop triggers the compilation heuristic which compiles the whole body for the imported px.

vtjnash commented 8 years ago

It's not #265, although it has been making my PR for #265 harder and less accurate.

brenhinkeller commented 2 years ago

Updating the reduced example for modern syntax

module A
export px
const px = ""
end
using .A

struct B
    value::Float64
    B(v::Float64) = new(v)
end

begin
    px = 1.0

    println(px, ", ", typeof(px))

    b = B(px)

    for ii=1:1 #no error if loop is removed
    end
end

it looks like this does still happen today (1.8.3 and 1.9.0-alpha1), except the error is now:

julia> begin
           px = 1.0

           println(px, ", ", typeof(px))

           b = B(px)

           for ii=1:1 #no error if loop is removed
           end
       end
ERROR: cannot assign a value to variable A.px from module Main
Stacktrace:
 [1] top-level scope
   @ ./REPL[4]:2

whereas no error if run in a fresh session without the loop:

julia> begin
           px = 1.0

           println(px, ", ", typeof(px))

           b = B(px)
       end
1.0, Float64
B(1.0)