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

Subroutine Type Annotations #182

Merged
merged 10 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
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
10 changes: 10 additions & 0 deletions pyteal/ast/subroutine.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ def __init__(
)
)

for var, var_type in implementation.__annotations__.items():
if var_type is not Expr:
stub = "Return" if var == "return" else ("parameter " + var)

raise TealInputError(
"Function has {} of disallowed type {}. Only type Expr is allowed".format(
stub, var_type
)
)

self.implementation = implementation
self.implementationParams = sig.parameters
self.returnType = returnType
Expand Down
55 changes: 48 additions & 7 deletions pyteal/ast/subroutine_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ def fn10Args(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
lam2Args = lambda a1, a2: Return()
lam10Args = lambda a1, a2, a3, a4, a5, a6, a7, a8, a9, a10: Return()

def fnWithExprAnnotations(a: Expr, b: Expr) -> Expr:
return Return()

def fnWithOnlyReturnExprAnnotations(a, b) -> Expr:
return Return()

def fnWithOnlyArgExprAnnotations(a: Expr, b: Expr):
return Return()

def fnWithPartialExprAnnotations(a, b: Expr) -> Expr:
return Return()

cases = (
(fn0Args, 0, "fn0Args"),
(fn1Args, 1, "fn1Args"),
Expand All @@ -37,6 +49,10 @@ def fn10Args(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
(lam1Args, 1, "<lambda>"),
(lam2Args, 2, "<lambda>"),
(lam10Args, 10, "<lambda>"),
(fnWithExprAnnotations, 2, "fnWithExprAnnotations"),
(fnWithOnlyReturnExprAnnotations, 2, "fnWithOnlyReturnExprAnnotations"),
(fnWithOnlyArgExprAnnotations, 2, "fnWithOnlyArgExprAnnotations"),
(fnWithPartialExprAnnotations, 2, "fnWithPartialExprAnnotations"),
)

for (fn, numArgs, name) in cases:
Expand Down Expand Up @@ -72,18 +88,43 @@ def fnWithKeywordArgs(a, *, b):
def fnWithVariableArgs(a, *b):
return Return()

def fnWithNonExprReturnAnnotation(a, b) -> TealType.uint64:
return Return()

def fnWithNonExprParamAnnotation(a, b: TealType.uint64):
return Return()

cases = (
1,
None,
fnWithDefaults,
fnWithKeywordArgs,
fnWithVariableArgs,
(1, "TealInputError('Input to SubroutineDefinition is not callable'"),
(None, "TealInputError('Input to SubroutineDefinition is not callable'"),
(
fnWithDefaults,
"TealInputError('Function has a parameter with a default value, which is not allowed in a subroutine: b'",
),
(
fnWithKeywordArgs,
"TealInputError('Function has a parameter type that is not allowed in a subroutine: parameter b with type KEYWORD_ONLY'",
),
(
fnWithVariableArgs,
"TealInputError('Function has a parameter type that is not allowed in a subroutine: parameter b with type VAR_POSITIONAL'",
),
(
fnWithNonExprReturnAnnotation,
"TealInputError('Function has Return of disallowed type TealType.uint64. Only type Expr is allowed'",
),
(
fnWithNonExprParamAnnotation,
"TealInputError('Function has parameter b of disallowed type TealType.uint64. Only type Expr is allowed'",
),
)

for case in cases:
with pytest.raises(TealInputError):
for case, msg in cases:
with pytest.raises(TealInputError) as e:
SubroutineDefinition(case, TealType.none)

assert msg in str(e), "failed for case [{}]".format(case)


def test_subroutine_declaration():
cases = (
Expand Down