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

unification unifies different but identical types #418

Closed
canndrew opened this issue Nov 24, 2021 · 8 comments · Fixed by #3900 or #6206
Closed

unification unifies different but identical types #418

canndrew opened this issue Nov 24, 2021 · 8 comments · Fixed by #3900 or #6206
Assignees
Labels
compiler General compiler. Should eventually become more specific as the issue is triaged

Comments

@canndrew
Copy link
Contributor

  • module0.sw:
library module0;
pub struct Thing {}

impl Thing {
    pub fn new() -> Self {
        Thing {}
    }
}
  • module1.sw:
library module1;
pub struct Thing {}

impl Thing {
    pub fn new() -> Self {
        Thing {}
    }
}
  • main.sw:
script;
dep module0;
dep module1;

fn main() {
    let mut x = module0::~Thing::new();
    let y = module1::~Thing::new();
    x = y;
}

To compile this you need to relax the rules in hll.pest to allow parsing zero-field structs. This code will then compile despite the fact that module0::Thing and module1::Thing are two different types.

@canndrew canndrew changed the title unifications unifies different but identical types unification unifies different but identical types Nov 24, 2021
@canndrew
Copy link
Contributor Author

@othro / @sezna: What causes this is that if two different types have the same name and the same fields then their TypeInfos are identical. One way to half-fix this would be to change the name field in TypeInfo::Enum/TypeInfo::Struct to be a full path (eg. library::module::type_name rather than just type_name). However we'll still end up running into the same problem if there are multiple versions of a dependency being built (eg. we depend on dep-a-v0.1 and dep-b, but dep-b depends on dep-a-v0.2). Instead I think TypeInfo::Enum/Struct need to be replaced with a variant that contains a declaration id that uniquely identifies the type.

However that unique declaration id seems like it might be the intended purpose of the TypeId type. Which brings me to another concern: Right now we are very greedily allocating TypeIds. For instance every expression of type bool gets a unique TypeId which maps to TypeInfo::Bool (or a TypeInfo::Ref to bool, or a reference-to-reference-to-bool, etc.). This is pretty inefficient and it isn't necessary. The way I see it, TypeId could be replaced with a type Type that looks like:

enum Type {
    Bool,
    /* other primitive types, contracts, etc. */

    Nominal(DeclId),
    Unknown(UnknownTypeId),
}

Where we then have a HashMap/Vec that maps UnknownTypeIds to their inferred type, only once they are inferred. That is Type::Unknown replaces TypeInfo::Ref, TypeInfo::Unknown is removed, and we use Type everywhere where we currently use TypeId.

Thoughts?

@otrho
Copy link
Contributor

otrho commented Nov 26, 2021

TypeId is meant to be a Copy tag for the type, a cheap way to declare on the spot what type some expression is if known -- e.g., literals, function arguments or expressions with type ascriptions -- or that it is Unknown. Then the unification process resolves all the types which are the same and catches type errors when they're not. This is essentially the inference process -- declare types we know from the source, call everything else Unknown, resolve things in the end.

So TypeId is designed to be allocated like crazy. The alternative is to look up the TypeId for the type we want all the time which only saves us some space in a hash map and takes more time.

I don't think changing the type inference algorithm is the solution here. I think just adding the full path to the declaration is good enough now, without having to worry about dependency hell yet.

@sezna
Copy link
Contributor

sezna commented Nov 26, 2021

It looks to me like Type::Unknown(UnknownTypeId) is isomorphic to TypeInfo::Ref(id), in that it says it is a reference to some other ID that may or may not be known at this particular time.

Since we don't even support dependency versions yet (no registry) the deps issue is an issue we can punt into the future. I think the answer here is to use a CallPath for the type name to prevent false unification of similar but identical structs.

@emilyaherbert emilyaherbert self-assigned this Dec 20, 2021
@emilyaherbert
Copy link
Contributor

Since we don't even support dependency versions yet (no registry) the deps issue is an issue we can punt into the future. I think the answer here is to use a CallPath for the type name to prevent false unification of similar but identical structs.

This is what I will be implementing.

@adlerjohn adlerjohn added the compiler General compiler. Should eventually become more specific as the issue is triaged label Dec 23, 2021
@adlerjohn adlerjohn moved this to Todo in Fuel Network Jan 6, 2022
@sezna
Copy link
Contributor

sezna commented Mar 14, 2022

@emilyaherbert @canndrew was this closed by #472? Is this still an issue?

@emilyaherbert
Copy link
Contributor

This is still an issue, TypeInfo just uses Idents and an not CallPaths. Probably an oversight of the #472 PR as I expect there is undefined behavior in the type system right now, if there are multiple similar definitions.

@emilyaherbert emilyaherbert removed their assignment Apr 5, 2022
@esdrubal esdrubal self-assigned this Jan 30, 2023
esdrubal added a commit that referenced this issue Feb 1, 2023
esdrubal added a commit that referenced this issue Feb 1, 2023
tritao added a commit that referenced this issue Feb 3, 2023
With these changes `TyStructDeclaration` and `TyEnumDeclaration` now
have a call path instead of a name.

This is required before changing the JSON ABI to use enum and struct
types with call paths instead of only names which can be duplicate.

This also fixes #418 by changing `Unifier` to compare `CallPath`'s
instead of `Ident`'s for enums and structs.

Closes #418

---------

Co-authored-by: João Matos <joao@tritao.eu>
@github-project-automation github-project-automation bot moved this from Todo to Done in Fuel Network Feb 3, 2023
eightfilms pushed a commit that referenced this issue Feb 7, 2023
With these changes `TyStructDeclaration` and `TyEnumDeclaration` now
have a call path instead of a name.

This is required before changing the JSON ABI to use enum and struct
types with call paths instead of only names which can be duplicate.

This also fixes #418 by changing `Unifier` to compare `CallPath`'s
instead of `Ident`'s for enums and structs.

Closes #418

---------

Co-authored-by: João Matos <joao@tritao.eu>
esdrubal added a commit that referenced this issue Feb 7, 2023
The issue is that the module in which a struct or enum is can be
imported with different callpaths.

For instance we could have a struct with callpath
`my_script::data_structures::SomeStruct` in a module and in another
module as `my_script::eq_impls::data_structures::SomeStruct`. This makes
callpaths unreliable to compare declarations.

Closes #3998

Reopens #418

Disables tests multiple_enums_with_the_same_name and
multiple_structs_with_the_same_name.
mohammadfawaz added a commit that referenced this issue Feb 7, 2023
## Description

The issue is that struct or enum can be imported with different
callpaths depending the module they are imported from.

For instance we could have a struct with callpath
`my_script::data_structures::SomeStruct` in a module and in another
module as `my_script::eq_impls::data_structures::SomeStruct`. This makes
callpaths unreliable to compare declarations.

Closes #3998

Reopens #418

Disables tests multiple_enums_with_the_same_name and
multiple_structs_with_the_same_name because they relied in callpath
comparisons to work.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.

Co-authored-by: Mohammad Fawaz <mohammadfawaz89@gmail.com>
@esdrubal
Copy link
Contributor

esdrubal commented Feb 7, 2023

#4007 reverted the fix that closed this issue, thus I am reopening it.
When this issue is fixed multiple_enums_with_the_same_name and multiple_structs_with_the_same_name tests should be re-enabled.

@esdrubal esdrubal reopened this Feb 7, 2023
@github-project-automation github-project-automation bot moved this from Done to In Progress in Fuel Network Feb 7, 2023
esdrubal added a commit that referenced this issue Jul 1, 2024
Two disabled test that were preventing #418 from beeing closed, are now fixed.

Closes #418
esdrubal added a commit that referenced this issue Jul 1, 2024
Two disabled tests preventing #418 from being closed, are now fixed.

Closes #418
@esdrubal
Copy link
Contributor

esdrubal commented Jul 2, 2024

Closing this issue as the tests mentioned previously are now enabled and passing.

@esdrubal esdrubal closed this as completed Jul 2, 2024
@github-project-automation github-project-automation bot moved this from In Progress to Done in Fuel Network Jul 2, 2024
IGI-111 pushed a commit that referenced this issue Jul 2, 2024
## Description

Two disabled tests preventing #418 from being closed, are now fixed.

Closes #418

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler General compiler. Should eventually become more specific as the issue is triaged
Projects
Status: Done
6 participants