Skip to content

Commit

Permalink
Forbid impossible pattern matching on generic capabilities (ponylang#…
Browse files Browse the repository at this point in the history
…2499)

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 authored and dipinhora committed Jun 5, 2018
1 parent 3238836 commit f2ca4e5
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 185 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 @@ -277,7 +277,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 @@ -320,7 +320,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 @@ -335,7 +335,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
Loading

0 comments on commit f2ca4e5

Please sign in to comment.