Skip to content
Closed
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
50 changes: 50 additions & 0 deletions aas_core_codegen/golang/transpilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,56 @@ def transform_function_call(
for arg_node, arg in zip(node.args, args)
]

for i, (arg_node, argument) in enumerate(
zip(node.args, func_type.func.arguments)
):
source_type = intermediate_type_inference.beneath_optional(
self.type_map[arg_node]
)
target_type = intermediate.beneath_optional(argument.type_annotation)
if not (
isinstance(func_type.func, intermediate.TranspilableVerification)
and not argument.mutable
and isinstance(
source_type, intermediate_type_inference.ListTypeAnnotation
)
and isinstance(target_type, intermediate.ListTypeAnnotation)
and isinstance(
source_type.items, intermediate_type_inference.OurTypeAnnotation
)
and isinstance(target_type.items, intermediate.OurTypeAnnotation)
and isinstance(source_type.items.our_type, intermediate.Class)
and isinstance(target_type.items.our_type, intermediate.Class)
and source_type.items.our_type is not target_type.items.our_type
and source_type.items.our_type.is_subclass_of(
target_type.items.our_type
)
):
continue

# NOTE (chris-koo):
# Go slices are invariant even when their item interfaces inherit.
# We convert only mismatching read-only arguments, preserving nil.
source_slice = self._our_type_name(
golang_naming.interface_name(source_type.items.our_type.name)
)
target_slice = self._our_type_name(
golang_naming.interface_name(target_type.items.our_type.name)
)
args[i] = Stripped(
f"""\
func(items []{source_slice}) []{target_slice} {{
{I}if items == nil {{
{II}return nil
{I}}}
{I}result := make([]{target_slice}, len(items))
{I}for i, item := range items {{
{II}result[i] = item
{I}}}
{I}return result
}}({args[i]})"""
)

args_joined = ", ".join(args)

# Apply heuristic for breaking the lines
Expand Down
26 changes: 25 additions & 1 deletion dev/test_data/common_meta_models/list_of_classes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enum import Enum
from typing import List
from typing import List, Optional, Sequence

from icontract import invariant

Expand All @@ -17,6 +17,30 @@ def __init__(self, name: str) -> None:
self.name = name


@verification
def items_are_some(items: Sequence[Abstract_item]) -> bool:
"""Check a read-only list of base-class instances."""
return all(isinstance(item, Some_item) for item in items)


@verification
def some_items_are_some(items: Sequence[Some_item]) -> bool:
"""Pass a list of descendants to a base-class list parameter."""
return items_are_some(items)


@verification
def optional_some_items_are_some(items: Optional[Sequence[Some_item]]) -> bool:
"""Preserve an optional descendant list passed to an optional parameter."""
return optional_items_are_some(items)


@verification
def optional_items_are_some(items: Optional[Sequence[Abstract_item]]) -> bool:
"""Check a possibly missing read-only list of base-class instances."""
return items is None or items_are_some(items)


class Another_item(Abstract_item):
serial_number: int

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,127 @@ SymbolTable(
named_unions=[],
constants=[],
constants_by_name=...,
verification_functions=[],
verification_functions=[
TranspilableVerification(
name='items_are_some',
visibility='PUBLIC',
arguments=[
Argument(
name='items',
type_annotation=ListTypeAnnotation(
items=OurTypeAnnotation(
our_type='Reference to our type Abstract_item',
parsed=...),
parsed=...),
default=None,
mutable=False,
parsed=...)],
returns=PrimitiveTypeAnnotation(
a_type='BOOL',
parsed=...),
description=DescriptionOfSignature(
summary='<paragraph>Check a read-only list of base-class instances.</paragraph>',
remarks=[],
arguments_by_name=[],
returns=None,
parsed=...),
contracts=Contracts(
preconditions=[],
snapshots=[],
postconditions=[]),
parsed=...,
arguments_by_name=...),
TranspilableVerification(
name='some_items_are_some',
visibility='PUBLIC',
arguments=[
Argument(
name='items',
type_annotation=ListTypeAnnotation(
items=OurTypeAnnotation(
our_type='Reference to our type Some_item',
parsed=...),
parsed=...),
default=None,
mutable=False,
parsed=...)],
returns=PrimitiveTypeAnnotation(
a_type='BOOL',
parsed=...),
description=DescriptionOfSignature(
summary='<paragraph>Pass a list of descendants to a base-class list parameter.</paragraph>',
remarks=[],
arguments_by_name=[],
returns=None,
parsed=...),
contracts=Contracts(
preconditions=[],
snapshots=[],
postconditions=[]),
parsed=...,
arguments_by_name=...),
TranspilableVerification(
name='optional_some_items_are_some',
visibility='PUBLIC',
arguments=[
Argument(
name='items',
type_annotation=OptionalTypeAnnotation(
value=ListTypeAnnotation(
items=OurTypeAnnotation(
our_type='Reference to our type Some_item',
parsed=...),
parsed=...),
parsed=...),
default=None,
mutable=False,
parsed=...)],
returns=PrimitiveTypeAnnotation(
a_type='BOOL',
parsed=...),
description=DescriptionOfSignature(
summary='<paragraph>Preserve an optional descendant list passed to an optional parameter.</paragraph>',
remarks=[],
arguments_by_name=[],
returns=None,
parsed=...),
contracts=Contracts(
preconditions=[],
snapshots=[],
postconditions=[]),
parsed=...,
arguments_by_name=...),
TranspilableVerification(
name='optional_items_are_some',
visibility='PUBLIC',
arguments=[
Argument(
name='items',
type_annotation=OptionalTypeAnnotation(
value=ListTypeAnnotation(
items=OurTypeAnnotation(
our_type='Reference to our type Abstract_item',
parsed=...),
parsed=...),
parsed=...),
default=None,
mutable=False,
parsed=...)],
returns=PrimitiveTypeAnnotation(
a_type='BOOL',
parsed=...),
description=DescriptionOfSignature(
summary='<paragraph>Check a possibly missing read-only list of base-class instances.</paragraph>',
remarks=[],
arguments_by_name=[],
returns=None,
parsed=...),
contracts=Contracts(
preconditions=[],
snapshots=[],
postconditions=[]),
parsed=...,
arguments_by_name=...)],
verification_functions_by_name=...,
meta_model=MetaModel(
description=None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,42 @@ class RecursiveVerification : public IVerification {
const std::shared_ptr<types::IClass>& instance_;
}; // class RecursiveVerification

// region Verification functions

/// \brief Check a read-only list of base-class instances.
bool ItemsAreSome(
const std::vector<
std::shared_ptr<types::IAbstractItem>
>& items
);

/// \brief Pass a list of descendants to a base-class list parameter.
bool SomeItemsAreSome(
const std::vector<
std::shared_ptr<types::ISomeItem>
>& items
);

/// \brief Preserve an optional descendant list passed to an optional parameter.
bool OptionalSomeItemsAreSome(
const common::optional<
std::vector<
std::shared_ptr<types::ISomeItem>
>
>& items
);

/// \brief Check a possibly missing read-only list of base-class instances.
bool OptionalItemsAreSome(
const common::optional<
std::vector<
std::shared_ptr<types::IAbstractItem>
>
>& items
);

// endregion Verification functions

} // namespace verification
/**@}*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,68 @@ Error::Error(

// endregion struct Error

// region Verification functions

bool ItemsAreSome(
const std::vector<
std::shared_ptr<types::IAbstractItem>
>& items
) {
return (
common::All(
[&](const std::shared_ptr<types::IAbstractItem>& item) -> bool {
return types::IsSomeItem(*item);
},
items
)
);
}

bool SomeItemsAreSome(
const std::vector<
std::shared_ptr<types::ISomeItem>
>& items
) {
return (
ItemsAreSome(
items
)
);
}

bool OptionalSomeItemsAreSome(
const common::optional<
std::vector<
std::shared_ptr<types::ISomeItem>
>
>& items
) {
return (
OptionalItemsAreSome(
items
)
);
}

bool OptionalItemsAreSome(
const common::optional<
std::vector<
std::shared_ptr<types::IAbstractItem>
>
>& items
) {
return (
(
(!(items.has_value()))
|| ItemsAreSome(
(*items)
)
)
);
}

// endregion Verification functions

namespace {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,48 @@ namespace dummy
/// </example>
public static class Verification
{
/// <summary>
/// Check a read-only list of base-class instances.
/// </summary>
public static bool ItemsAreSome(
List<IAbstractItem> items
)
{
return items.All(
item => item is Our.ISomeItem);
} // public static bool ItemsAreSome

/// <summary>
/// Pass a list of descendants to a base-class list parameter.
/// </summary>
public static bool SomeItemsAreSome(
List<ISomeItem> items
)
{
return Verification.ItemsAreSome(items);
} // public static bool SomeItemsAreSome

/// <summary>
/// Preserve an optional descendant list passed to an optional parameter.
/// </summary>
public static bool OptionalSomeItemsAreSome(
List<ISomeItem>? items
)
{
return Verification.OptionalItemsAreSome(items);
} // public static bool OptionalSomeItemsAreSome

/// <summary>
/// Check a possibly missing read-only list of base-class instances.
/// </summary>
public static bool OptionalItemsAreSome(
List<IAbstractItem>? items
)
{
return (items == null)
|| Verification.ItemsAreSome(items);
} // public static bool OptionalItemsAreSome

/// <summary>
/// Hash allowed enum values for efficient validation of enums.
/// </summary>
Expand Down
Loading
Loading