Skip to content

Commit

Permalink
Forbid impossible pattern matching on generic capabilities
Browse files Browse the repository at this point in the history
This changes the capability rules for pattern matching from

"some possible instantiation of the operand is a subtype of some
possible instantation of the pattern"

to

"every possible instantiation of the operand is a subtype of every
possible instantiation of the pattern".

In practice this makes the compiler issue an error when a pattern can
only ever match for some reification of the generic capability. Code
that uses this kind of pattern matching should now use `iftype`
instead.

This doesn't fix any safety issues.
  • Loading branch information
Benoit Vey committed Jan 17, 2018
1 parent 35af399 commit 1cfa808
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 150 deletions.
140 changes: 0 additions & 140 deletions src/libponyc/type/cap.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,146 +362,6 @@ bool is_cap_sub_cap_bound(token_id sub, token_id subalias, token_id super,
return false;
}

bool is_cap_match_cap(token_id operand_cap, token_id operand_eph,
token_id pattern_cap, token_id pattern_eph)
{
// Transform the cap based on the aliasing info.
cap_aliasing(&operand_cap, &operand_eph);
cap_aliasing(&pattern_cap, &pattern_eph);

if(pattern_eph == TK_EPHEMERAL)
{
// Operand must be ephemeral.
if(operand_eph != TK_EPHEMERAL)
return false;
}

if((operand_cap == pattern_cap) || (pattern_cap == TK_TAG))
return true;

// Some instantiaion of the operand refcap must be a subtype of some
// instantiation of the pattern refcap.
switch(operand_cap)
{
case TK_ISO:
case TK_CAP_SEND:
case TK_CAP_ANY:
switch(pattern_cap)
{
case TK_ISO:
case TK_TRN:
case TK_REF:
case TK_VAL:
case TK_BOX:
case TK_CAP_READ:
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

case TK_TRN:
switch(pattern_cap)
{
case TK_REF:
case TK_VAL:
case TK_BOX:
case TK_CAP_READ:
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

case TK_REF:
switch(pattern_cap)
{
case TK_BOX:
case TK_CAP_READ:
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

case TK_VAL:
case TK_CAP_SHARE:
switch(pattern_cap)
{
case TK_BOX:
case TK_CAP_READ:
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

case TK_BOX:
switch(pattern_cap)
{
case TK_CAP_READ:
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

case TK_TAG:
switch(pattern_cap)
{
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

case TK_CAP_READ:
case TK_CAP_ALIAS:
switch(pattern_cap)
{
case TK_REF:
case TK_VAL:
case TK_BOX:
case TK_CAP_SHARE:
case TK_CAP_SEND:
case TK_CAP_ALIAS:
case TK_CAP_ANY:
return true;

default: {}
}
break;

default: {}
}

return false;
}

bool is_cap_compat_cap(token_id left_cap, token_id left_eph,
token_id right_cap, token_id right_eph)
{
Expand Down
7 changes: 0 additions & 7 deletions src/libponyc/type/cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@ bool is_cap_sub_cap_constraint(token_id sub, token_id subalias, token_id super,
bool is_cap_sub_cap_bound(token_id sub, token_id subalias, token_id super,
token_id supalias);

/**
* Some possible instantiation of the operand is a subtype of some possible
* instantiation of the pattern.
*/
bool is_cap_match_cap(token_id operand_cap, token_id operand_eph,
token_id pattern_cap, token_id pattern_eph);

/**
* Every possible instantiation of the left side is locally compatible with
* every possible instantiation of the right side. This relationship is
Expand Down
6 changes: 3 additions & 3 deletions src/libponyc/type/matchtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ static matchtype_t is_nominal_match_entity(ast_t* operand, ast_t* pattern,

// If the operand does provide the pattern, but the operand refcap can't
// match the pattern refcap, deny the match.
if(!is_cap_match_cap(ast_id(o_cap), ast_id(o_eph), tcap, teph))
if(!is_cap_sub_cap(ast_id(o_cap), ast_id(o_eph), tcap, teph))
return MATCHTYPE_DENY;

// Otherwise, accept the match.
Expand Down Expand Up @@ -270,7 +270,7 @@ static matchtype_t is_entity_match_trait(ast_t* operand, ast_t* pattern,

// If the operand does provide the pattern, but the operand refcap can't
// match the pattern refcap, deny the match.
if(!is_cap_match_cap(ast_id(o_cap), ast_id(o_eph), tcap, teph))
if(!is_cap_sub_cap(ast_id(o_cap), ast_id(o_eph), tcap, teph))
return MATCHTYPE_DENY;

// Otherwise, accept the match.
Expand All @@ -285,7 +285,7 @@ static matchtype_t is_trait_match_trait(ast_t* operand, ast_t* pattern,
AST_GET_CHILDREN(pattern, p_pkg, p_id, p_typeargs, p_cap, p_eph);

// If the operand refcap can't match the pattern refcap, deny the match.
if(!is_cap_match_cap(ast_id(o_cap), ast_id(o_eph),
if(!is_cap_sub_cap(ast_id(o_cap), ast_id(o_eph),
ast_id(p_cap), ast_id(p_eph)))
return MATCHTYPE_DENY;

Expand Down

0 comments on commit 1cfa808

Please sign in to comment.