Skip to content

Commit

Permalink
Add subtypes to unions/isects in the reach pass
Browse files Browse the repository at this point in the history
This change ensures that unions and intersections pick up their
subtypes during the reachability analysis.

Closes ponylang#1474.
  • Loading branch information
Benoit Vey committed Feb 15, 2017
1 parent ab41349 commit 969c9de
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ All notable changes to the Pony compiler and standard library will be documented
- Compiler assertion failure during type checking
- Runtime memory allocator bug
- Compiler crash on tuple sending generation (issue #1546)
- Compiler crash due to incorrect subtype assignment (issue #1474)

### Added

Expand Down
57 changes: 39 additions & 18 deletions src/libponyc/reach/reach.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,12 @@ static void add_types_to_trait(reach_t* r, reach_type_t* t,
size_t i = HASHMAP_BEGIN;
reach_type_t* t2;

ast_t* def = (ast_t*)ast_data(t->ast);
bool interface = ast_id(def) == TK_INTERFACE;
bool interface = false;
if(ast_id(t->ast) == TK_NOMINAL)
{
ast_t* def = (ast_t*)ast_data(t->ast);
interface = ast_id(def) == TK_INTERFACE;
}

while((t2 = reach_types_next(&r->types, &i)) != NULL)
{
Expand All @@ -397,7 +401,8 @@ static void add_types_to_trait(reach_t* r, reach_type_t* t,
{
reach_type_cache_put(&t->subtypes, t2);
reach_type_cache_put(&t2->subtypes, t);
add_methods_to_type(r, t, t2, opt);
if(ast_id(t->ast) == TK_NOMINAL)
add_methods_to_type(r, t, t2, opt);
}
break;

Expand All @@ -414,24 +419,38 @@ static void add_traits_to_type(reach_t* r, reach_type_t* t,

while((t2 = reach_types_next(&r->types, &i)) != NULL)
{
if(ast_id(t2->ast) != TK_NOMINAL)
continue;
if(ast_id(t2->ast) == TK_NOMINAL)
{
ast_t* def = (ast_t*)ast_data(t2->ast);

ast_t* def = (ast_t*)ast_data(t2->ast);
switch(ast_id(def))
{
case TK_INTERFACE:
case TK_TRAIT:
if(is_subtype(t->ast, t2->ast, NULL, opt))
{
reach_type_cache_put(&t->subtypes, t2);
reach_type_cache_put(&t2->subtypes, t);
add_methods_to_type(r, t2, t, opt);
}
break;

switch(ast_id(def))
{
case TK_INTERFACE:
case TK_TRAIT:
if(is_subtype(t->ast, t2->ast, NULL, opt))
{
reach_type_cache_put(&t->subtypes, t2);
reach_type_cache_put(&t2->subtypes, t);
add_methods_to_type(r, t2, t, opt);
}
break;
default: {}
}
} else {
switch(ast_id(t2->ast))
{
case TK_UNIONTYPE:
case TK_ISECTTYPE:
if(is_subtype(t->ast, t2->ast, NULL, opt))
{
reach_type_cache_put(&t->subtypes, t2);
reach_type_cache_put(&t2->subtypes, t);
}
break;

default: {}
default: {}
}
}
}
}
Expand Down Expand Up @@ -556,6 +575,8 @@ static reach_type_t* add_isect_or_union(reach_t* r, ast_t* type,
t->underlying = ast_id(t->ast);
t->type_id = r->next_type_id++;

add_types_to_trait(r, t, opt);

ast_t* child = ast_child(type);

while(child != NULL)
Expand Down
54 changes: 54 additions & 0 deletions test/libponyc/reach.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <gtest/gtest.h>
#include <platform.h>

#include <reach/reach.h>

#include "util.h"


#define TEST_COMPILE(src) DO(test_compile(src, "reach"))


class ReachTest : public PassTest
{};


TEST_F(ReachTest, IsectHasSubtypes)
{
const char* src =
"trait TA\n"
" fun a() => None\n"

"trait TB\n"
" fun b() => None\n"

"actor Main is (TA & TB)\n"
" new create(env: Env) =>\n"
" let ab: (TA & TB) = this\n"
" ab.a()\n"
" ab.b()";

TEST_COMPILE(src);

ast_t* ab_ast = type_of("ab");
ASSERT_NE(ab_ast, (void*)NULL);

reach_t* reach = compile->reach;
reach_type_t* ab_reach = reach_type(reach, ab_ast);
ASSERT_NE(ab_reach, (void*)NULL);

size_t i = HASHMAP_BEGIN;
reach_type_t* subtype;

bool found = false;
while((subtype = reach_type_cache_next(&ab_reach->subtypes, &i)) != NULL)
{
if(subtype->name == stringtab("Main"))
{
found = true;
break;
}
}

ASSERT_TRUE(found);
}

0 comments on commit 969c9de

Please sign in to comment.