-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Infer `tracked` for parameters that are referenced in the public signatures of the defining class. e.g. ```scala 3 class OrdSet(val ord: Ordering) { type Set = List[ord.T] def empty: Set = Nil implicit class helper(s: Set) { def add(x: ord.T): Set = x :: remove(x) def remove(x: ord.T): Set = s.filter(e => ord.compare(x, e) != 0) def member(x: ord.T): Boolean = s.exists(e => ord.compare(x, e) == 0) } } ``` In the example above, `ord` is referenced in the signatures of the public members of `OrdSet`, so a `tracked` modifier will be inserted automatically. Aldo generalize the condition for infering tracked for context bounds. Explicit `using val` witnesses will now also be `tracked` by default. This implementation should be safe with regards to not introducing spurious cyclic reference errors. Current limitations (I'll create separate issues for them, once this is merged): - Inferring `tracked` for given classes is done after the desugaring to class + def, so the def doesn't know about `tracked` being set on the original constructor parameter. This might be worked around by watching the original symbol or adding an attachment pointer to the implicit wrapper. ```scala 3 given mInst: (c: C) => M: def foo: c.T = c.foo ``` - Passing parameters as an **inferred** `tracked` arguments in parents doesn't work, since forcing a parent (term) isn't safe. This can be replaced with a lint that is checked after Namer.
- Loading branch information
1 parent
312c89a
commit 019d203
Showing
9 changed files
with
347 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import scala.language.experimental.modularity | ||
|
||
trait T: | ||
type Self | ||
type X | ||
def foo: Self | ||
|
||
class D[C](using wd: C is T) | ||
class E(using we: Int is T) | ||
|
||
def Test = | ||
given w: Int is T: | ||
def foo: Int = 42 | ||
type X = Long | ||
val d = D(using w) | ||
summon[d.wd.X =:= Long] // error | ||
val e = E(using w) | ||
summon[e.we.X =:= Long] // error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import scala.language.experimental.modularity | ||
import scala.language.future | ||
|
||
trait Ordering { | ||
type T | ||
def compare(t1:T, t2: T): Int | ||
} | ||
|
||
class SetFunctor(val ord: Ordering) { | ||
type Set = List[ord.T] | ||
def empty: Set = Nil | ||
|
||
implicit class helper(s: Set) { | ||
def add(x: ord.T): Set = x :: remove(x) | ||
def remove(x: ord.T): Set = s.filter(e => ord.compare(x, e) != 0) | ||
def member(x: ord.T): Boolean = s.exists(e => ord.compare(x, e) == 0) | ||
} | ||
} | ||
|
||
object Test { | ||
val orderInt = new Ordering { | ||
type T = Int | ||
def compare(t1: T, t2: T): Int = t1 - t2 | ||
} | ||
|
||
val IntSet = new SetFunctor(orderInt) | ||
import IntSet.* | ||
|
||
def main(args: Array[String]) = { | ||
val set = IntSet.empty.add(6).add(8).add(23) | ||
assert(!set.member(7)) | ||
assert(set.member(8)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import scala.language.experimental.modularity | ||
|
||
trait T: | ||
type Self | ||
type X | ||
def foo: Self | ||
|
||
class D[C](using val wd: C is T) | ||
class E(using val we: Int is T) | ||
|
||
def Test = | ||
given w: Int is T: | ||
def foo: Int = 42 | ||
type X = Long | ||
val d = D(using w) | ||
summon[d.wd.X =:= Long] | ||
val e = E(using w) | ||
summon[e.we.X =:= Long] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import scala.language.experimental.modularity | ||
import scala.language.future | ||
|
||
trait WithValue { type Value = Int } | ||
|
||
case class Year(value: Int) extends WithValue { | ||
val x: Value = 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import scala.language.experimental.modularity | ||
import scala.language.future | ||
|
||
import collection.mutable | ||
|
||
/// A parser combinator. | ||
trait Combinator[T]: | ||
|
||
/// The context from which elements are being parsed, typically a stream of tokens. | ||
type Context | ||
/// The element being parsed. | ||
type Element | ||
|
||
extension (self: T) | ||
/// Parses and returns an element from `context`. | ||
def parse(context: Context): Option[Element] | ||
end Combinator | ||
|
||
final case class Apply[C, E](action: C => Option[E]) | ||
final case class Combine[A, B](first: A, second: B) | ||
|
||
object test: | ||
|
||
class apply[C, E] extends Combinator[Apply[C, E]]: | ||
type Context = C | ||
type Element = E | ||
extension(self: Apply[C, E]) | ||
def parse(context: C): Option[E] = self.action(context) | ||
|
||
def apply[C, E]: apply[C, E] = new apply[C, E] | ||
|
||
class combine[A, B]( | ||
val f: Combinator[A], | ||
val s: Combinator[B] { type Context = f.Context} | ||
) extends Combinator[Combine[A, B]]: | ||
type Context = f.Context | ||
type Element = (f.Element, s.Element) | ||
extension(self: Combine[A, B]) | ||
def parse(context: Context): Option[Element] = ??? | ||
|
||
def combine[A, B]( | ||
_f: Combinator[A], | ||
_s: Combinator[B] { type Context = _f.Context} | ||
) = new combine[A, B](_f, _s) | ||
// cast is needed since the type of new combine[A, B](_f, _s) | ||
// drops the required refinement. | ||
|
||
extension [A] (buf: mutable.ListBuffer[A]) def popFirst() = | ||
if buf.isEmpty then None | ||
else try Some(buf.head) finally buf.remove(0) | ||
|
||
@main def hello: Unit = { | ||
val source = (0 to 10).toList | ||
val stream = source.to(mutable.ListBuffer) | ||
|
||
val n = Apply[mutable.ListBuffer[Int], Int](s => s.popFirst()) | ||
val m = Combine(n, n) | ||
|
||
val c = combine( | ||
apply[mutable.ListBuffer[Int], Int], | ||
apply[mutable.ListBuffer[Int], Int] | ||
) | ||
val r = c.parse(m)(stream) // was type mismatch, now OK | ||
val rc: Option[(Int, Int)] = r | ||
} |
Oops, something went wrong.