Skip to content

Commit

Permalink
Don't mark ivar as nilable if super present and non-nilable (#4863)
Browse files Browse the repository at this point in the history
If initialize calls super and declares instance var that has already
been typed as non-nilable by an ancestor, it'll be non-nilable in the
child class.

Fixes #4764
  • Loading branch information
maxfierke authored and RX14 committed Aug 31, 2017
1 parent 280e822 commit f4cb617
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
19 changes: 19 additions & 0 deletions spec/compiler/semantic/initialize_spec.cr
Expand Up @@ -731,4 +731,23 @@ describe "Semantic: initialize" do
),
"no argument named 'x'"
end

it "doesn't type ivar as nilable if super call present and parent has already typed ivar (#4764)" do
assert_type(%(
class Foo
def initialize(@a = 1)
end
end
class Bar < Foo
def initialize
super
end
def initialize(@a)
end
end
Bar.new
)) { types["Bar"] }
end
end
4 changes: 4 additions & 0 deletions src/compiler/crystal/semantic/type_declaration_processor.cr
Expand Up @@ -498,6 +498,10 @@ struct Crystal::TypeDeclarationProcessor
# It's non-nilable if it's initialized outside
next if initialized_outside?(owner, instance_var)

# If an initialize with an ivar calls super and an ancestor has already
# typed the instance var as non-nilable
next if info.def.calls_super? && ancestor_non_nilable.try(&.includes?(instance_var))

unless info.try(&.instance_vars.try(&.includes?(instance_var)))
all_assigned = false
# Rememebr that this variable wasn't initialized here, and later error
Expand Down

0 comments on commit f4cb617

Please sign in to comment.