Skip to content

Conversation

@hrkrshnn
Copy link
Contributor

@hrkrshnn hrkrshnn commented Aug 16, 2021

Closes #11531

TODO

  • Cleanup all TODOs
  • Implement AST import and Export
  • Write more tests
  • Documentation
  • NatSpec?
  • ANTLR grammar

@hrkrshnn hrkrshnn changed the title User defined types User defined value types Aug 16, 2021
@hrkrshnn hrkrshnn force-pushed the user-defined-types branch from 73c2097 to 1b14c2c Compare August 16, 2021 12:46
@hrkrshnn hrkrshnn force-pushed the user-defined-types branch 3 times, most recently from 54411e7 to 99ea7e8 Compare August 17, 2021 17:15
``==`` is disallowed. One can use operators or bound member functions by explicitly converting it
to the underlying type.

The following example demonstrates a custom type ``MyAddress`` which is an abstraction over the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we use an example that also shows the usefulness of this concept?

@hrkrshnn hrkrshnn force-pushed the user-defined-types branch from 99ea7e8 to 4a030b4 Compare August 18, 2021 10:59
type MyAddress is address;

function f() pure {
// TODO Should we allow explicit conversions from literals?
Copy link
Contributor Author

@hrkrshnn hrkrshnn Aug 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes. This is similar to how newtype semantics work in haskell and rust (?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too sure about it - wouldn't it create ambiguities? We have to at least check that implicit conversion from the literal to the underlying type is possible.

@hrkrshnn hrkrshnn force-pushed the user-defined-types branch from 4a030b4 to 55683a7 Compare August 18, 2021 11:03
}
bool nameable() const override { return m_underlyingType.nameable(); }

std::string toString(bool _short) const override { return "UserDefinedValueType(" + m_underlyingType.toString(_short) + ")"; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this also include the name of the type? (as we do for struct)

}
else if (m_actualType->category() == Category::UserDefinedValueType)
{
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(*m_actualType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(*m_actualType);
auto const& userDefined = dynamic_cast<UserDefinedValueType const&>(*m_actualType);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the const here is redundant, isn't it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, but may be nice to mention it - we usually do.

if (kind == FunctionType::Kind::Wrap)
solAssert(argumentType->isImplicitlyConvertibleTo(userDefinedType->underlyingType()), "");

acceptAndConvert(*arguments[0], *function.parameterTypes()[0], true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to do cleanup?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you assert that the implicit conversion is possible, please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the cleanup and added one more assert.

Type const* argumentType = arguments.at(0)->annotation().type;
solAssert(argumentType, "");
FunctionType::Kind kind = functionType->kind();
auto userDefinedType = kind == FunctionType::Kind::Wrap ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be easier and less confusing to retrieve this from _functionCall.expression? Maybe not.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On that note test cases for stuff like (MyType).wrap and the like would be good.

@hrkrshnn hrkrshnn force-pushed the user-defined-types branch 3 times, most recently from b2b01ae to 0cdac18 Compare September 8, 2021 16:59
+-------------------------------+-----------------------------------------------------------------------------+
|:ref:`enum<enums>` |``uint8`` |
+-------------------------------+-----------------------------------------------------------------------------+
|:ref:`user defined value types |exactly as its underlying value type |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the "exactly" was not meant literally. The text above table says "on the right column the ABI types that represent them", so it should be enough to say "its underlying value type" or "the underlying value type".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

case FunctionType::Kind::Wrap:
case FunctionType::Kind::Unwrap:
{
typeCheckFunctionGeneralChecks(_functionCall, functionType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice!

else
solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType, "");

define(_functionCall, *arguments.at(0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually skips one conversion - but would be fine for me, since the conversion is a no-op (and I hope it stays like that).

@hrkrshnn hrkrshnn merged commit 8a37f56 into develop Sep 9, 2021
@hrkrshnn hrkrshnn deleted the user-defined-types branch September 9, 2021 08:28
* User defined value types, i.e., custom types, for example, `type MyInt is int`. Allows creating a
* zero cost abstraction over value type with stricter type requirements.
*/
class UserDefinedValueTypeDefinition: public Declaration
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this is a really bad name for the node :-D - but well.

Comment on lines +3 to +6
(MyInt).wrap;
(MyInt).wrap(5);
(MyInt).unwrap;
(MyInt).unwrap(MyInt.wrap(5));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Syntactically this is really not interesting - this should be a semantics test!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it here: #11914

Copy link
Contributor

@fulldecent fulldecent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fixed math library claims the division function is to the "nearest integer" but actually it rounds down.

@hrkrshnn
Copy link
Contributor Author

hrkrshnn commented Sep 9, 2021

@fulldecent Thanks for noticing. Will update the comment.

@fulldecent
Copy link
Contributor

Thank you! Looks good now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User-defined value types

5 participants