Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Describe how field resolution works. #144

Open
wants to merge 1 commit into
base: scip-ruby/master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions docs/scip-ruby/FieldResolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Field resolution

In Sorbet, fields on classes can be declared or undeclared.

Declared fields are defined with `@fieldName = T.let(initialValue, type)`
in the special [`initialize` method](https://www.rubyguides.com/2019/01/ruby-initialize-method/),
inside a class or a module.

Undeclared fields are those which lack such a definition.

Sorbet automatically propagates declared fields down inheritance hierarchies
but not down module inclusions. For example, with code like:

```ruby
class C
def initialize
@x = T.let(0, Integer)
@z = T.let(0, Integer)
end

def set_w
@w = 0
end
end

module M
def initialize
@y = T.let(0, Integer)
@z = T.let(0, Integer)
end
end

class D < C
include M
def sum
@w + @x + @y + @z
end
end
```

In `C`:
- `@x` and `@z` will have `SymbolRef`s corresponding to `C#@x` and `C#@z` respectively.
- `@w` be a `Magic_undeclaredFieldStub`.

In `M#initialize`:
- `@y` and `@z` will have `SymbolRef`s corresponding to `M#@y` and `M#@z` respectively.

In `D#sum`:
- `@w` and `@y` will be `Magic_undeclaredFieldStub`.
- `@x` and `@z` will have `SymbolRef`s corresponding to `C#@x` and `C#@z` respectively.

Notice that Sorbet is using the same symbol across classes
when a declared field is accessed.
This is similar to how scip-java works.

The constraints we have in scip-ruby are a little different,
because fields may not be declared,
and we need this to work in a cross-repo setting.

In scip-ruby, we do something a little different.
- The symbol name always corresponds to the containing class or module name.
- If the symbol is in a class, we will emit an `is_definition` relationship
between the symbol and the matching symbol in the closest ancestor class,
as well as `is_reference` relationships for matching symbols in the inclusion
hierarchy.
- If the symbol is in a module, we will emit an `is_definition`
- We will emit an `is_definition` relationship between the symbol
and the matching symbol in the closest parent class (or module,
if we're in a module),
and `is_reference` relationships between the symbol
and matching symbols in