Skip to content
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
4 changes: 1 addition & 3 deletions packages/builtin/any.pony
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
interface tag Any

interface tag AnyNoCheck
interface tag Any
2 changes: 1 addition & 1 deletion packages/builtin/array.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Array[A : AnyNoCheck] is Seq[A]
class Array[\allowstruct\ A] is Seq[A]
"""
Contiguous, resizable memory to store elements of type A.

Expand Down
8 changes: 4 additions & 4 deletions packages/builtin/c_fixed_sized_array.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
struct CFixedSizedArray[A: AnyNoCheck, _size: USize]
struct CFixedSizedArray[\allowstruct\ A, _size: USize]
"""
Contiguous, fixed sized memory to store elements of type A.
Useful for FFI interfaces and does not contain any extra
Expand Down Expand Up @@ -211,7 +211,7 @@ fun pairs(): CFixedSizedArrayPairs[A, _size, this->CFixedSizedArray[A, _size]]^
CFixedSizedArrayPairs[A, _size, this->CFixedSizedArray[A, _size]](this)


class CFixedSizedArrayKeys[A, _size: USize, B: CFixedSizedArray[A, _size] #read] is Iterator[USize]
class CFixedSizedArrayKeys[A, _size: USize, \allowstruct\ B: CFixedSizedArray[A, _size] #read] is Iterator[USize]
let _array: B
var _i: USize

Expand All @@ -230,7 +230,7 @@ class CFixedSizedArrayKeys[A, _size: USize, B: CFixedSizedArray[A, _size] #read]
end


class CFixedSizedArrayValues[A, _size: USize, B: CFixedSizedArray[A, _size] #read] is Iterator[B->A]
class CFixedSizedArrayValues[A, _size: USize, \allowstruct\ B: CFixedSizedArray[A, _size] #read] is Iterator[B->A]
let _array: B
var _i: USize

Expand All @@ -245,7 +245,7 @@ class CFixedSizedArrayValues[A, _size: USize, B: CFixedSizedArray[A, _size] #rea
_array(_i = _i + 1)?


class CFixedSizedArrayPairs[A, _size: USize, B: CFixedSizedArray[A, _size] #read] is Iterator[(USize, B->A)]
class CFixedSizedArrayPairs[A, _size: USize, \allowstruct\ B: CFixedSizedArray[A, _size] #read] is Iterator[(USize, B->A)]
let _array: B
var _i: USize

Expand Down
2 changes: 1 addition & 1 deletion packages/builtin/fixed_sized_array.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class FixedSizedArray[A: AnyNoCheck, _size: USize]
class FixedSizedArray[\allowstruct\ A, _size: USize]
"""
Contiguous, fixed sized memory to store elements of type A.
"""
Expand Down
2 changes: 1 addition & 1 deletion packages/builtin/nullable_pointer.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
struct NullablePointer[A: AnyNoCheck]
struct NullablePointer[\allowstruct\ A]
"""
A NullablePointer[A] is used to encode a possibly-null type. It should
_only_ be used for structs that need to be passed to and from the C FFI.
Expand Down
6 changes: 3 additions & 3 deletions packages/builtin/pointer.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
struct Pointer[A: AnyNoCheck]
struct Pointer[\allowstruct\ A]
"""
A Pointer[A] is a raw memory pointer. It has no descriptor and thus can't be
included in a union or intersection, or be a subtype of any interface. Most
Expand All @@ -22,7 +22,7 @@ struct Pointer[A: AnyNoCheck]
"""
compile_intrinsic

new from_any[B: AnyNoCheck](from: B) =>
new from_any[\allowstruct\ B](from: B) =>
"""
Initializes from any type to a Pointer.
"""
Expand All @@ -46,7 +46,7 @@ struct Pointer[A: AnyNoCheck]
"""
compile_intrinsic

fun convert[B: AnyNoCheck](): this->Pointer[B] =>
fun convert[\allowstruct\ B](): this->Pointer[B] =>
"""
Convert from Pointer[A] to Pointer[B].
"""
Expand Down
1 change: 1 addition & 0 deletions src/libponyc/ast/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ DEF(typearg);
// ID [COLON type] [ASSIGN typearg]
DEF(typeparam);
AST_NODE(TK_TYPEPARAM);
ANNOTATE(annotations);
TOKEN("name", TK_ID);
IF(TK_COLON, RULE("type constraint", type));
IF(TK_ASSIGN, RULE("default type argument", typearg));
Expand Down
1 change: 1 addition & 0 deletions src/libponyc/ast/treecheckdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ GROUP(value_formal_literal,
int_literal, float_literal, bool_literal, string);

RULE(value_formal_arg,
HAS_DATA
CHILD(value_formal_literal, seq, comptime_expr)
HAS_TYPE(type),
TK_VALUEFORMALARG);
Expand Down
10 changes: 10 additions & 0 deletions src/libponyc/expr/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,16 @@ static bool method_call(pass_opt_t* opt, ast_t* ast)
return false;

AST_GET_CHILDREN(type, cap, typeparams, params, result);

// This is needed because the return type might be unprocessed
// because the method appears later on in the AST.
// We must run the expression pass here because the return type
// is being set here and used for inferring the assigned type
if(ast_visit(&result, NULL, pass_expr, opt, PASS_EXPR) != AST_OK)
{
return false;
}

ast_settype(ast, result);

return true;
Expand Down
11 changes: 11 additions & 0 deletions src/libponyc/expr/literal.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,17 @@ static bool coerce_literal_to_type(ast_t** astp, ast_t* target_type,
break;
}

case TK_VALUEFORMALARG:
{
ast_t* l = ast_child(literal_expr);
if(!coerce_literal_to_type(&l, target_type, chain, opt,
report_errors))
return false;

ast_settype(literal_expr, ast_type(l));
break;
}

default:
ast_error(opt->check.errors, literal_expr, "Internal error, coerce_literal_to_type node %s",
ast_get_print(literal_expr));
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/expr/reference.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ bool expr_typeref(pass_opt_t* opt, ast_t** astp)

// This is needed in order to evaluate the value type arguments and give them a type
// for type references. If Array or Pointer, skip the check.
if (ast_id(typeargs) != TK_NONE)
if(ast_id(typeargs) != TK_NONE)
{
ast_t* underlying_type = (ast_t*)ast_data(ast);
if((underlying_type != NULL) &&
Expand Down
63 changes: 34 additions & 29 deletions src/libponyc/type/reify.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,34 @@ static void reify_valueformalparamref(pass_opt_t* opt, ast_t** astp, ast_t* type

if(ast_id(typearg) == TK_VALUEFORMALARG)
{
ast_t* type = ast_childidx(found_typeparam, 1);
ast_settype(typearg, type);
ast_t* lit = ast_child(typearg);
ast_t* typeparam_type = ast_childidx(found_typeparam, 1);

ast_t* literal_type = ast_type(lit);
if(literal_type == NULL)
{
// Why do we need to run the pass_expr and coerce_literals here?
// When reifying and replacing the TK_VALUEFORMALPARAMREF with
// a TK_VALUEFORMALARG the literals might not have been processed
// yet becuase it originates from something later on in the AST tree

// Here we make literals out of the expression
if(ast_visit(&lit, NULL, pass_expr, opt, PASS_EXPR) != AST_OK)
{
pony_assert(false);
return;
}

// Let's coerce the literal
if(!coerce_literals(&lit, typeparam_type, opt))
{
pony_assert(false);
return;
}
}

ast_setdata(typearg, found_typeparam);
ast_settype(typearg, typeparam_type);
}
ast_replace(astp, typearg);
}
Expand Down Expand Up @@ -314,7 +340,10 @@ bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors,
opt->program_pass == PASS_EXPR)
{
ast_t* lit_child = ast_child(defarg);
pass_expr(&lit_child, opt);
if(ast_visit(&lit_child, NULL, pass_expr, opt, PASS_EXPR) != AST_OK)
{
return false;
}
}

ast_append(typeargs, defarg);
Expand Down Expand Up @@ -564,31 +593,6 @@ bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs,

while(typeparam != NULL)
{
// Check if the constraint is name "AnyNoCheck" which will
// skip any checks for the type parameter. This is used by
// the builtin types like Pointer and Array among others.
ast_t* constraint_id = NULL;
ast_t* ref_or_type = ast_childidx(typeparam, 1);
if(ast_id(ref_or_type) == TK_NOMINAL)
{
constraint_id = ast_childidx(ref_or_type, 1);
}
else if(ast_id(ref_or_type) == TK_TYPEPARAMREF)
{
ast_t* constraint = typeparam_constraint(ref_or_type);
if(constraint != NULL && ast_id(constraint) == TK_NOMINAL)
{
constraint_id = ast_childidx(constraint, 1);
}
}

if (constraint_id != NULL && strcmp(ast_name(constraint_id), "AnyNoCheck") == 0)
{
typeparam = ast_sibling(typeparam);
typearg = ast_sibling(typearg);
continue;
}

if (is_bare(typearg))
{
if(report_errors)
Expand All @@ -606,7 +610,7 @@ bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs,
{
ast_t* def = (ast_t*)ast_data(typearg);

if(ast_id(def) == TK_STRUCT)
if(ast_id(def) == TK_STRUCT && !ast_has_annotation(typeparam, "allowstruct"))
{
if(report_errors)
{
Expand Down Expand Up @@ -691,6 +695,7 @@ bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs,
if(ast_id(typearg) == TK_VALUEFORMALARG)
{
ast_t* literal = ast_child(typearg);

if (!coerce_literals(&literal, r_constraint, opt))
return false;

Expand Down
32 changes: 31 additions & 1 deletion src/libponyc/type/subtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,36 @@ static bool is_literal_equal(ast_t* a, ast_t* b)
return false;
}

static ast_t* get_valueformalarg_type(ast_t* ast)
{
ast_t* parent = ast_parent(ast);
ast_t* parent2 = ast_parent(parent);

ast_t* def = NULL;

switch(ast_id(parent2))
{
case TK_NOMINAL:
case TK_TYPEREF:
def = (ast_t*)ast_data(parent2);
break;

default:
pony_assert(false);
break;
}

size_t index = ast_index(ast);

ast_t* type_params = ast_childidx(def, 1);

ast_t* typeparam = ast_childidx(type_params, index);

ast_t* arg_type = ast_childidx(typeparam, 1);

return arg_type;
}

static bool is_eq_typeargs(ast_t* a, ast_t* b, errorframe_t* errorf,
pass_opt_t* opt)
{
Expand All @@ -282,7 +312,7 @@ static bool is_eq_typeargs(ast_t* a, ast_t* b, errorframe_t* errorf,
if (!is_literal_equal(lit_a, lit_b))
ret = false;

if (!is_eqtype(ast_type(lit_a), ast_type(lit_b), errorf, opt))
if (!is_eqtype(get_valueformalarg_type(a_arg), get_valueformalarg_type(b_arg), errorf, opt))
ret = false;
}
else
Expand Down
8 changes: 4 additions & 4 deletions test/full-program-tests/iftype-else-if-true/main.pony
Original file line number Diff line number Diff line change
Expand Up @@ -70,28 +70,28 @@ actor Main

false

fun is_class[A: AnyNoCheck](): Bool =>
fun is_class[\allowstruct\ A](): Bool =>
iftype A <: class then
true
else
false
end

fun is_struct[A: AnyNoCheck](): Bool =>
fun is_struct[\allowstruct\ A](): Bool =>
iftype A <: struct then
true
else
false
end

fun is_primitive[A: AnyNoCheck](): Bool =>
fun is_primitive[\allowstruct\ A](): Bool =>
iftype A <: primitive then
true
else
false
end

fun is_class_or_primitive[A: AnyNoCheck](): Bool =>
fun is_class_or_primitive[\allowstruct\ A](): Bool =>
iftype A <: (class | struct) then
true
else
Expand Down
2 changes: 1 addition & 1 deletion test/libponyc/iftype.cc
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ TEST_F(IftypeTest, TestUnderlyingType)
" foo[S1]()\n"
" foo[P1]()\n"

" fun foo[A: AnyNoCheck]() =>\n"
" fun foo[\\allowstruct\\ A]() =>\n"
" iftype A <: class then\n"
" None\n"
" end\n"
Expand Down
16 changes: 4 additions & 12 deletions test/libponyc/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,12 @@ static const char* const _builtin =
" => None\n"
"primitive None\n"
"interface tag Any\n"
"interface tag AnyNoCheck\n"
"primitive Bool\n"
" new create(a: Bool) => a\n"
" fun op_and(a: Bool): Bool => this and a\n"
" fun op_not(): Bool => not this\n"
"class val String\n"
"struct Pointer[A: AnyNoCheck]\n"
"struct Pointer[\\allowstruct\\ A]\n"
" new create() => compile_intrinsic\n"
" fun tag is_null(): Bool => compile_intrinsic\n"
"interface Seq[A]\n"
Expand All @@ -103,7 +102,7 @@ static const char* const _builtin =
"class ArrayValues[A]\n"
" fun ref has_next(): Bool => false\n"
" fun ref next(): A ? => error\n"
"class Array[A: AnyNoCheck] is Seq[A]\n"
"class Array[\\allowstruct\\ A] is Seq[A]\n"
" var _size: USize = 0\n"
" var _alloc: USize = 0\n"
" var _ptr: Pointer[A] = Pointer[A]\n"
Expand All @@ -117,16 +116,9 @@ static const char* const _builtin =
" fun ref next(): A ?\n"
"primitive DoNotOptimise\n"
" fun apply[A](obj: A) => compile_intrinsic\n"
"struct NullablePointer[A]\n"
"struct NullablePointer[\\allowstruct\\ A]\n"
" new create(that: A) => compile_intrinsic\n"
"struct RuntimeOptions\n"
"struct box Optional[A: AnyNoCheck]"
" new none() => compile_intrinsic\n"
" new create(init: A) => compile_intrinsic\n"
" fun is_none() : Bool => compile_intrinsic\n"
" fun is_some(): Bool => compile_intrinsic\n"
" fun apply(): A? => error\n"
" fun get_no_check(): A => compile_intrinsic\n";
"struct RuntimeOptions\n";


void Main_runtime_override_defaults_oo(void* opt)
Expand Down
Loading
Loading