Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8295d8ccae7a
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a34f32f77b8a
Choose a head ref
  • 4 commits
  • 7 files changed
  • 1 contributor

Commits on Dec 12, 2016

  1. Implement optimized ARGF#gets. Fixes #3667

    Ary Borenszweig committed Dec 12, 2016
    Copy the full SHA
    44a2fc4 View commit details
  2. Don't consider var as nilable if conditionally assigned inside initia…

    …lize, but has initializer. Fixes #3669
    Ary Borenszweig committed Dec 12, 2016
    Copy the full SHA
    08fa553 View commit details
  3. IO::Sized: optimized gets

    Ary Borenszweig committed Dec 12, 2016
    Copy the full SHA
    d17c248 View commit details
  4. HTTP::UnknownLengthContent: optimized gets

    Ary Borenszweig committed Dec 12, 2016
    Copy the full SHA
    a34f32f View commit details
Showing with 118 additions and 7 deletions.
  1. +18 −0 spec/compiler/semantic/instance_var_spec.cr
  2. +34 −0 spec/std/io/argf_spec.cr
  3. +9 −0 spec/std/io/sized_spec.cr
  4. +13 −7 src/compiler/crystal/semantic/main_visitor.cr
  5. +6 −0 src/http/content.cr
  6. +27 −0 src/io/argf.cr
  7. +11 −0 src/io/sized.cr
18 changes: 18 additions & 0 deletions spec/compiler/semantic/instance_var_spec.cr
Original file line number Diff line number Diff line change
@@ -4560,4 +4560,22 @@ describe "Semantic: instance var" do
Foo.new.a
)) { bool }
end

it "doesn't consider var as nilable if conditionally assigned inside initialize, but has initializer (#3669)" do
assert_type(%(
class Foo
@x = 0
def initialize
@x = 1 if 1 == 2
end
def x
@x
end
end
Foo.new.x
)) { int32 }
end
end
34 changes: 34 additions & 0 deletions spec/std/io/argf_spec.cr
Original file line number Diff line number Diff line change
@@ -37,4 +37,38 @@ describe IO::ARGF do
str = argf.gets(5)
str.should eq("12345")
end

describe "gets" do
it "reads from STDIN if ARGV isn't specified" do
argv = [] of String
stdin = IO::Memory.new("hello\nworld\n")

argf = IO::ARGF.new argv, stdin
argf.gets.should eq("hello\n")
argf.gets.should eq("world\n")
argf.gets.should be_nil
end

it "reads from ARGV if specified" do
path1 = "#{__DIR__}/../data/argf_test_file_1.txt"
path2 = "#{__DIR__}/../data/argf_test_file_2.txt"
stdin = IO::Memory.new("")
argv = [path1, path2]

argf = IO::ARGF.new argv, stdin
argv.should eq([path1, path2])

argf.gets.should eq("12345\n")
argv.should eq([path2])

argf.gets.should eq("67890\n")
argv.empty?.should be_true

argf.gets.should be_nil

argv << path1
str = argf.gets
str.should eq("12345\n")
end
end
end
9 changes: 9 additions & 0 deletions spec/std/io/sized_spec.cr
Original file line number Diff line number Diff line change
@@ -90,4 +90,13 @@ describe "IO::Sized" do
sized.read_byte.should eq('c'.ord)
sized.read_byte.should be_nil
end

it "gets" do
io = IO::Memory.new "foo\nbar\nbaz"
sized = IO::Sized.new(io, read_size: 9)
sized.gets.should eq("foo\n")
sized.gets.should eq("bar\n")
sized.gets.should eq("b")
sized.gets.should be_nil
end
end
20 changes: 13 additions & 7 deletions src/compiler/crystal/semantic/main_visitor.cr
Original file line number Diff line number Diff line change
@@ -773,12 +773,16 @@ module Crystal
if @is_initialize
var_name = target.name

meta_var = (@meta_vars[var_name] ||= new_meta_var(var_name))
meta_var.bind_to value
meta_var.assigned_to = true
# Don't track instance variables nilabilty (for example, if they were
# just assigned inside a branch) if they have an initializer
unless scope.has_instance_var_initializer?(var_name)
meta_var = (@meta_vars[var_name] ||= new_meta_var(var_name))
meta_var.bind_to value
meta_var.assigned_to = true

simple_var = MetaVar.new(var_name)
simple_var.bind_to(target)
simple_var = MetaVar.new(var_name)
simple_var.bind_to(target)
end

used_ivars_in_calls_in_initialize = @used_ivars_in_calls_in_initialize
if (found_self = @found_self_in_initialize_call) || (used_ivars_node = used_ivars_in_calls_in_initialize.try(&.[var_name]?)) || (@block_nest > 0 && !@vars.has_key?(var_name))
@@ -791,9 +795,11 @@ module Crystal
ivar.bind_to program.nil_var
end

@vars[var_name] = simple_var
if simple_var
@vars[var_name] = simple_var

check_exception_handler_vars var_name, value
check_exception_handler_vars var_name, value
end
end
end

6 changes: 6 additions & 0 deletions src/http/content.cr
Original file line number Diff line number Diff line change
@@ -34,6 +34,12 @@ module HTTP
@io.read_byte
end

def gets(delimiter : Char, limit : Int) : String?
return super if @encoding

@io.gets(delimiter, limit)
end

def write(slice : Slice(UInt8))
raise IO::Error.new "Can't write to UnknownLengthContent"
end
27 changes: 27 additions & 0 deletions src/io/argf.cr
Original file line number Diff line number Diff line change
@@ -31,6 +31,33 @@ class IO::ARGF
read_count
end

# :nodoc:
def gets(delimiter : Char, limit : Int) : String?
return super if @encoding

first_initialize unless @initialized

if current_io = @current_io
string = current_io.gets(delimiter, limit)
if !string && !@read_from_stdin
current_io.close
if @argv.empty?
@current_io = nil
else
read_next_argv
string = gets(delimiter, limit)
end
end
elsif !@read_from_stdin && !@argv.empty?
read_next_argv
string = gets(delimiter, limit)
else
string = nil
end

string
end

def write(slice : Slice(UInt8))
raise IO::Error.new "can't write to ARGF"
end
11 changes: 11 additions & 0 deletions src/io/sized.cr
Original file line number Diff line number Diff line change
@@ -49,6 +49,17 @@ module IO
end
end

def gets(delimiter : Char, limit : Int) : String?
check_open

return super if @encoding
return nil if @read_remaining == 0

string = @io.gets(delimiter, Math.min(limit, @read_remaining))
@read_remaining -= string.bytesize if string
string
end

def write(slice : Slice(UInt8))
raise IO::Error.new "Can't write to IO::Sized"
end