File tree Expand file tree Collapse file tree 3 files changed +58
-1
lines changed
src/compiler/crystal/semantic Expand file tree Collapse file tree 3 files changed +58
-1
lines changed Original file line number Diff line number Diff line change @@ -448,6 +448,47 @@ describe "Semantic: if" do
448448 CRYSTAL
449449 end
450450
451+ it " doesn't add Nil to var assigned in && condition with method call (#15739)" do
452+ assert_type(<<-CRYSTAL , inject_primitives: true) { int32 }
453+ def foo
454+ if true && (x = 1) == 1
455+ x
456+ else
457+ 0
458+ end
459+ end
460+ foo
461+ CRYSTAL
462+ end
463+
464+ it " types var assigned in && condition correctly when used after (#15739)" do
465+ assert_type(<<-CRYSTAL , inject_primitives: true) { int32 }
466+ def bar : Int32
467+ 1
468+ end
469+
470+ def foo
471+ if true && (x = bar) > 0
472+ x
473+ else
474+ 0
475+ end
476+ end
477+ foo
478+ CRYSTAL
479+ end
480+
481+ it " allows chained comparisons of 4+ expressions (#16361)" do
482+ assert_type(<<-CRYSTAL , inject_primitives: true) { bool }
483+ def a; 1; end
484+ def b; 2; end
485+ def c; 3; end
486+ def d; 4; end
487+
488+ a < b < c < d
489+ CRYSTAL
490+ end
491+
451492 it " includes pointer types in falsey branch" do
452493 assert_type(<<-CRYSTAL ) { nilable union_of bool, pointer_of(int32), int32 }
453494 def foo
Original file line number Diff line number Diff line change @@ -287,6 +287,14 @@ module Crystal
287287 new node, TruthyFilter .instance
288288 end
289289
290+ def self.truthy_var (name : String )
291+ new_filters = new
292+ filter = TruthyFilter .instance
293+ new_filters.pos[name] = filter
294+ new_filters.neg[name] = filter.not
295+ new_filters
296+ end
297+
290298 def self.and (filters1, filters2)
291299 return nil if filters1.nil? && filters2.nil?
292300
Original file line number Diff line number Diff line change @@ -2017,7 +2017,15 @@ module Crystal
20172017 # `a && b` is expanded to `a ? b : a`
20182018 # We don't use `else_type_filters` because if `a` is a temp var
20192019 # assignment then `cond_type_filters` would contain more information
2020- @type_filters = TypeFilters .and (cond_type_filters, then_type_filters)
2020+ and_filters = TypeFilters .and (cond_type_filters, then_type_filters)
2021+ # For variables assigned in the then branch but not in the condition,
2022+ # add truthy filters so they're properly narrowed when the && result
2023+ # is used as a condition (#15739)
2024+ then_vars.each do |name , _ |
2025+ next if cond_vars.has_key?(name)
2026+ and_filters = TypeFilters .and (and_filters, TypeFilters .truthy_var(name))
2027+ end
2028+ @type_filters = and_filters
20212029 when .or ?
20222030 # `a || b` is expanded to `a ? a : b`
20232031 @type_filters = TypeFilters .or (cond_type_filters, else_type_filters)
You can’t perform that action at this time.
0 commit comments