Sorbet generates unreachable assignment for AR default attributes
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 873
- Forks
- 164
- Avg merge
- 4d 27m
- Merged PRs (30d)
- 9
Description
Referred from https://github.com/sorbet/sorbet/issues/6621
Input
Model:
# typed: strict
class Shortcode < ApplicationRecord
after_initialize :set_defaults, if: :new_record?
private
def set_defaults
self.code ||= SecureRandom.urlsafe_base64(10)
end
end
# == Schema Information
#
# Table name: shortcodes
#
# id :bigint not null, primary key
# code :string not null
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_shortcodes_on_code (code) UNIQUE
Migration:
class CreateShortcodes < ActiveRecord::Migration[7.0]
def change
create_table :shortcodes do |t|
t.string :code, null: false
t.index :code, unique: true
t.timestamps
end
end
end
Annotation RBI (generated by tapioca):
class Shortcode
include GeneratedAttributeMethods
extend GeneratedRelationMethods
private
# cut for length
module GeneratedAttributeMethods
# cut for length
sig { returns(::String) }
def code; end
sig { params(value: ::String).returns(::String) }
def code=(value); end
sig { returns(T::Boolean) }
def code?; end
sig { returns(T.nilable(::String)) }
def code_before_last_save; end
sig { returns(T.untyped) }
def code_before_type_cast; end
sig { returns(T::Boolean) }
def code_came_from_user?; end
sig { returns(T.nilable([::String, ::String])) }
def code_change; end
sig { returns(T.nilable([::String, ::String])) }
def code_change_to_be_saved; end
sig { returns(T::Boolean) }
def code_changed?; end
sig { returns(T.nilable(::String)) }
def code_in_database; end
sig { returns(T.nilable([::String, ::String])) }
def code_previous_change; end
sig { returns(T::Boolean) }
def code_previously_changed?; end
sig { returns(T.nilable(::String)) }
def code_previously_was; end
sig { returns(T.nilable(::String)) }
def code_was; end
sig { void }
def code_will_change!; end
end
end
Observed output
$ bundle exec srb tc
Indexing |=======================================================| ETA: 0h00m00s
Resolving |======================================================| ETA: 0h00m01s
app/models/shortcode.rb:7: This code is unreachable https://srb.help/700600m00s
7 | self.code ||= SecureRandom.urlsafe_base64(10)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/micropage.rb:7: This condition was always truthy (String)
7 | self.code ||= SecureRandom.urlsafe_base64(10)
^^^^^^^^^^^^^^^
Got String originating from:
app/models/shortcode.rb:7:
7 | self.short_code ||= SecureRandom.urlsafe_base64(10)
^^^^^^^^^^^^^^^
CFG+Inference |==================================================| ETA: 0h00m00s
Errors: 1
error Command failed with exit code 1.
Expected behavior
The check should have passed, because it is possible for self.short_code to be either nil or defined depending on how Shortcode.create! is called. You can call Shortcode.create!(code: "my_code") and create a record with code defined, and you can also call Shortcode.create! at which point line 7 above will assign a random code. The code is not unreachable.
Sorbet version: 0.5.10160
Tapioca version: 0.10.3
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the diagnostic with the Shortcode example in app/models/shortcode.rb by running bundle exec srb tc, then inspect the generated Tapioca RBI declarations shown in the issue. The issue is done when a valid Active Record default assignment no longer produces an unreachable-code error while the example still type-checks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100