Skip to content

Commit

Permalink
Type param constraints now respect default cap of the type.
Browse files Browse the repository at this point in the history
Prior to this change, any type named in a type constraint would
get an implicit cap of `#any` if no explicit cap was named.
The exception to this rule is primitives, which will use an implicit
cap of `val` in a type constraint (though I'm not sure why you'd
ever use a primitive as a type constraint to begin with).
In both cases, the default cap declared by the user in the type
declaration was being ignored, and this is the only context where
that happens, violating the principle of least surprise.
I also don't think this deviation is documented anywhere.

As a veteran pony programmer, this still surprises and annoys me
regularly when I run into it; I commonly make this mistake and
have to recompile with an explicit cap that matches my declared default cap.

Furthermore, using #any as a type parameter constraint is rarely what
you actually want (not constraining the cap at all turns out to not
let you do very much), so it doesn't make much sense to be the
implicit cap. To illustrate this, there isn't a single example of
a type constraint having a final cap of `#any` in the standard library.
The lines that have been affected by this change are all cases of using
type intersections where only one of the terms was being used to constrain
the cap.

After this change the default cap declared by the user will be
universally respected.

This is a breaking change for anyone who is relying on this behaviour.
  • Loading branch information
jemc committed Apr 30, 2018
1 parent 9222f08 commit 5224267
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 17 deletions.
2 changes: 1 addition & 1 deletion packages/collections/_test.pony
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ class iso _TestSort is UnitTest
[""; "%*&^*&^&"; "***"; "Hello"; "bar"; "f00"; "foo"; "foo"],
[""; "Hello"; "foo"; "bar"; "foo"; "f00"; "%*&^*&^&"; "***"])

fun test_sort[A: (Comparable[A] val & Stringable)](
fun test_sort[A: (Comparable[A] val & Stringable val)](
h: TestHelper,
sorted: Array[A],
unsorted: Array[A])
Expand Down
2 changes: 1 addition & 1 deletion packages/collections/persistent/map.pony
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use mut = "collections"

type Map[K: (mut.Hashable val & Equatable[K]), V: Any #share] is
type Map[K: (mut.Hashable val & Equatable[K] val), V: Any #share] is
HashMap[K, V, mut.HashEq[K]]
"""
A map that uses structural equality on the key.
Expand Down
2 changes: 1 addition & 1 deletion packages/collections/persistent/set.pony
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use mut = "collections"

type Set[A: (mut.Hashable val & Equatable[A])] is HashSet[A, mut.HashEq[A]]
type Set[A: (mut.Hashable val & Equatable[A] val)] is HashSet[A, mut.HashEq[A]]

type SetIs[A: Any #share] is HashSet[A, mut.HashIs[A]]

Expand Down
4 changes: 2 additions & 2 deletions packages/ponytest/test_helper.pony
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class val TestHelper
"""
_check_eq[A]("eq", expect, actual, msg, loc)

fun _check_eq[A: (Equatable[A] #read & Stringable)]
fun _check_eq[A: (Equatable[A] #read & Stringable #read)]
(check: String, expect: A, actual: A, msg: String, loc: SourceLoc)
: Bool
=>
Expand Down Expand Up @@ -221,7 +221,7 @@ class val TestHelper
"""
_check_ne[A]("ne", not_expect, actual, msg, loc)

fun _check_ne[A: (Equatable[A] #read & Stringable)]
fun _check_ne[A: (Equatable[A] #read & Stringable #read)]
(check: String, not_expect: A, actual: A, msg: String, loc: SourceLoc)
: Bool
=>
Expand Down
14 changes: 2 additions & 12 deletions src/libponyc/pass/names.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,18 +215,8 @@ static bool names_type(pass_opt_t* opt, ast_t** astp, ast_t* def)

if(tcap == TK_NONE)
{
if((opt->check.frame->constraint != NULL) ||
(opt->check.frame->iftype_constraint != NULL))
{
// A primitive constraint is a val, otherwise #any.
if(ast_id(def) == TK_PRIMITIVE)
tcap = TK_VAL;
else
tcap = TK_CAP_ANY;
} else {
// Use the default capability.
tcap = ast_id(def_cap);
}
// Use the default capability.
tcap = ast_id(def_cap);
}

ast_setid(cap, tcap);
Expand Down

0 comments on commit 5224267

Please sign in to comment.