vyper icon indicating copy to clipboard operation
vyper copied to clipboard

cannot import structs

Open mhorsley30896 opened this issue 3 years ago • 6 comments

Suppose I have a simple contract that records a user input in a struct.

# @version ^0.3.0

struct A_Struct:
	a: uint256
	b: uint256

struct_map: public(HashMap[uint256, A_Struct])

struct_idx: uint256

@external
def __init__():
	pass

@external
def add_struct(_a: uint256, _b: uint256):
	
	struct_inst: A_Struct = A_Struct({a: _a, b:_b})

	self.struct_map[self.struct_idx] = struct_inst

	self.struct_idx += 1

Now if I export the interface for this contract such that another contract can use it

vyper -f interface contracts/MyContract.vy

# Functions

@external
def add_struct(_a: uint256, _b: uint256):
    pass

@view
@external
def struct_map(arg0: uint256) -> A_Struct:
    pass

If I save this output into an interface file called MyInterface.vy and then write a second contract

# @version ^0.3.0

import interfaces.MyInterface as MC

my_contract: MC

@external
def __init__(mc_address: address):

	self.my_contract = MC(mc_address)

@external
def other_add_struct(_a: uint256, _b: uint256):

	self.my_contract.add_struct(_a, _b)

Then when I try and compile this I get an error

Unhandled exception in 'contracts/MyOtherContract.vy':
UnknownType: Compilation failed with the following errors:

UnknownType: No builtin or user-defined type named 'A_Struct'
  contract "MC", function "struct_map", line 9:33 
       8 @external
  ---> 9 def struct_map(arg0: uint256) -> A_Struct:
  ----------------------------------------^
      10     pass

This error can be removed if I delete A_Struct as the return type for struct_map in MyInterface.vy. Is this expected behaviour or am I misunderstanding something around structs and interfaces?

mhorsley30896 avatar Feb 17 '22 22:02 mhorsley30896

@mhorsley30896 struct definitions aren't exported from interface definitions. right now the thing to do is redefine struct A_Struct again from MyOtherContract.vy -

import interfaces.MyInterface as MC

# ...
struct A_Struct:
	a: uint256
	b: uint256
# ...

my_contract: MC

I'm leaving this issue open though so we can track a discussion about changing the semantics here.

charles-cooper avatar Feb 18 '22 02:02 charles-cooper

@charles-cooper you also have to define A_Struct in the interface as well? It does seem like overkill (and a little unpythonic) to have to keep copying and pasting struct definitions into arbitrary numbers of files

mhorsley30896 avatar Feb 18 '22 17:02 mhorsley30896

@charles-cooper you also have to define A_Struct in the interface as well? It does seem like overkill (and a little unpythonic) to have to keep copying and pasting struct definitions into arbitrary numbers of files

yep you need to define in both places -- and I agree about the overkill part

charles-cooper avatar Feb 18 '22 18:02 charles-cooper

A side note: ABI encoding defines structs as tuples of their members (although there is some undefined behavior with tight packing), so one way to handle this might to implicitly convert structs to and from tuples, so that the interfaces matched up

fubuloubu avatar Feb 19 '22 07:02 fubuloubu

meeting notes: we should allow this, A_Struct would probably be referenced like MC.A_Struct

charles-cooper avatar Mar 14 '22 21:03 charles-cooper

+1 for ability to import structs -- would be very helpful!

hadfieldn avatar Aug 27 '22 23:08 hadfieldn

implemented in https://github.com/vyperlang/vyper/pull/3663

charles-cooper avatar Mar 07 '24 15:03 charles-cooper