# Attributes Resolution

[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/compiler/attribute_resolution.md%26commit_hash%3Dc6eb78a44de48735213413b2a28569fdc10466d0)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/compiler/attribute_resolution.md&commit_hash=c6eb78a44de48735213413b2a28569fdc10466d0)

Resolving attributes means, for example, given the expression `x.y`, determining the type of this entire expression. Therefore, the type of `x` must be determined, but the type of `x` may not be uniquely determined. In such cases, the type of `x.y` may still be determined, or it may fail. This is the problem of attribute resolution that this section deals with.

As a simple case, consider the expression `1.real` (`x == 1, y == real`). The type of `1` is `{1}`. `{1}` is a subtype of `Nat`, `Int` and `Obj`. Trace these types in turn to find the definition of `real`. In this case, it is found in `Int` (`Int.real: Int`). Thus the type of `x` is cast to `Int` and the type of `1.real` is `Int`.

Thus, if the type of `x` is uniquely determinable, inference proceeds in the order `x` -> `y`.
However, when the type of `x` cannot be uniquely determined, the type of `x` can be narrowed down from `y`.

For example:

```erg
consts c = c.co_consts
```

``co_consts`` is an attribute of type `Code`. This example was chosen just because a name that does not cover others. It is not the essence of what this function means.
Since the type of ``c`` is not specified, You may think inference is not possible, but it is (when the only type with ``co_consts`` in the namespace is `Code`).

Erg assigns a type variable when no variable type is specified.

```erg
consts: ?1
c: ?2
```

The type inferrer tries to determine the definition of `co_consts` from the type `?2`, but fails because `?2` is a type variable with no condition.
In such a case, [`get_attr_type_by_name`](https://github.com/erg-lang/erg/blob/b8a87c0591e5603c1afcfc54c073ab2101ff2857/crates/erg_compiler/context/inquire.rs#L2884) is called.
This method attempts to identify the type `?2` from the name `co_consts`, as opposed to before.
It succeeds only if the only type with `co_consts` in the namespace is `Code` (or all other types are supertype of Code).
Erg closes function type checking within a module, so even if a type with `co_consts` is defined outside the module, passing an instance of it to the `consts` function will result in an error (to make this possible, you must use `Structural`, described below). This constraint allows the `consts` function to infer.

When a class attribute is defined, the type inferrer keeps track of the "attribute" and "defining class, attribute type" pairs.
In the case of ``co_consts``, this pair is `{co_consts: {Code, List(Obj, _)}}`.

```erg
method_to_classes: {co_consts: [{Code, List(Obj, _)}], real: [{Int, Int}], times!: [{Nat, (self: Nat, proc!: () => NoneType) => NoneType}], ...}
```

Note that the value of the key-value pair is an array. Only if this array is of length 1, or has the smallest type element, the key is uniquely determined (otherwise a type error will occur).

Once the key is identified, the definition type is back-propagated to the type of ``?2``.

```erg
?2(<: Code).co_consts: List(Obj, _)
```

Finally, the type of `consts` is `Code -> List(Obj, _)`.

```erg
consts(c: Code): List(Obj, _) = c.co_consts
```
