forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check for parameter references in type bounds when infering tracked
- Loading branch information
1 parent
cc767f0
commit 0e218c1
Showing
6 changed files
with
281 additions
and
10 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
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,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 | ||
} |
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,55 @@ | ||
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) | ||
|
||
given apply[C, E]: Combinator[Apply[C, E]] with { | ||
type Context = C | ||
type Element = E | ||
extension(self: Apply[C, E]) { | ||
def parse(context: C): Option[E] = self.action(context) | ||
} | ||
} | ||
|
||
given combine[A, B](using | ||
val f: Combinator[A], | ||
val s: Combinator[B] { type Context = f.Context } | ||
): Combinator[Combine[A, B]] with { | ||
type Context = f.Context | ||
type Element = (f.Element, s.Element) | ||
extension(self: Combine[A, B]) { | ||
def parse(context: Context): Option[Element] = ??? | ||
} | ||
} | ||
|
||
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 r = m.parse(stream) // error: type mismatch, found `mutable.ListBuffer[Int]`, required `?1.Context` | ||
val rc: Option[(Int, Int)] = r | ||
// it would be great if this worked | ||
} |
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,82 @@ | ||
import scala.language.experimental.modularity | ||
import scala.language.future | ||
|
||
object typeparams: | ||
sealed trait Nat | ||
object Z extends Nat | ||
final case class S[N <: Nat]() extends Nat | ||
|
||
type Zero = Z.type | ||
type Succ[N <: Nat] = S[N] | ||
|
||
sealed trait Fin[N <: Nat] | ||
case class FZero[N <: Nat]() extends Fin[Succ[N]] | ||
case class FSucc[N <: Nat](pred: Fin[N]) extends Fin[Succ[N]] | ||
|
||
object Fin: | ||
def zero[N <: Nat]: Fin[Succ[N]] = FZero() | ||
def succ[N <: Nat](i: Fin[N]): Fin[Succ[N]] = FSucc(i) | ||
|
||
sealed trait Vec[A, N <: Nat] | ||
case class VNil[A]() extends Vec[A, Zero] | ||
case class VCons[A, N <: Nat](head: A, tail: Vec[A, N]) extends Vec[A, Succ[N]] | ||
|
||
object Vec: | ||
def empty[A]: Vec[A, Zero] = VNil() | ||
def cons[A, N <: Nat](head: A, tail: Vec[A, N]): Vec[A, Succ[N]] = VCons(head, tail) | ||
|
||
def get[A, N <: Nat](v: Vec[A, N], index: Fin[N]): A = (v, index) match | ||
case (VCons(h, _), FZero()) => h | ||
case (VCons(_, t), FSucc(pred)) => get(t, pred) | ||
|
||
def runVec(): Unit = | ||
val v: Vec[Int, Succ[Succ[Succ[Zero]]]] = Vec.cons(1, Vec.cons(2, Vec.cons(3, Vec.empty))) | ||
|
||
println(s"Element at index 0: ${Vec.get(v, Fin.zero)}") | ||
println(s"Element at index 1: ${Vec.get(v, Fin.succ(Fin.zero))}") | ||
println(s"Element at index 2: ${Vec.get(v, Fin.succ(Fin.succ(Fin.zero)))}") | ||
// println(s"Element at index 2: ${Vec.get(v, Fin.succ(Fin.succ(Fin.succ(Fin.zero))))}") // error | ||
|
||
// TODO(kπ) check if I can get it to work | ||
// object typemembers: | ||
// sealed trait Nat | ||
// object Z extends Nat | ||
// case class S() extends Nat: | ||
// type N <: Nat | ||
|
||
// type Zero = Z.type | ||
// type Succ[N1 <: Nat] = S { type N = N1 } | ||
|
||
// sealed trait Fin: | ||
// type N <: Nat | ||
// case class FZero[N1 <: Nat]() extends Fin: | ||
// type N = Succ[N1] | ||
// case class FSucc(tracked val pred: Fin) extends Fin: | ||
// type N = Succ[pred.N] | ||
|
||
// object Fin: | ||
// def zero[N1 <: Nat]: Fin { type N = Succ[N1] } = FZero[N1]() | ||
// def succ[N1 <: Nat](i: Fin { type N = N1 }): Fin { type N = Succ[N1] } = FSucc(i) | ||
|
||
// sealed trait Vec[A]: | ||
// type N <: Nat | ||
// case class VNil[A]() extends Vec[A]: | ||
// type N = Zero | ||
// case class VCons[A](head: A, tracked val tail: Vec[A]) extends Vec[A]: | ||
// type N = Succ[tail.N] | ||
|
||
// object Vec: | ||
// def empty[A]: Vec[A] = VNil() | ||
// def cons[A](head: A, tail: Vec[A]): Vec[A] = VCons(head, tail) | ||
|
||
// def get[A](v: Vec[A], index: Fin { type N = v.N }): A = (v, index) match | ||
// case (VCons(h, _), FZero()) => h | ||
// case (VCons(_, t), FSucc(pred)) => get(t, pred) | ||
|
||
// // def runVec(): Unit = | ||
// val v: Vec[Int] = Vec.cons(1, Vec.cons(2, Vec.cons(3, Vec.empty))) | ||
|
||
// println(s"Element at index 0: ${Vec.get(v, Fin.zero)}") | ||
// println(s"Element at index 1: ${Vec.get(v, Fin.succ(Fin.zero))}") | ||
// println(s"Element at index 2: ${Vec.get(v, Fin.succ(Fin.succ(Fin.zero)))}") | ||
// // println(s"Element at index 2: ${Vec.get(v, Fin.succ(Fin.succ(Fin.succ(Fin.zero))))}") |
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