Skip to content

Commit eac9a56

Browse files
committed
Fix typing of RefinedTypes with watching parents
If a refined type has a parent type watching some other type, the parent should not be mapped to Object. Previously, the parent counted as `isEmpty` which caused this mapping. Also: Complete and cleanup hylolib tests
1 parent 9236a24 commit eac9a56

12 files changed

+198
-12
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
22062206
}
22072207

22082208
def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(using Context): TypTree = {
2209-
val tpt1 = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else typedAheadType(tree.tpt)
2209+
val tpt1 = if tree.tpt == EmptyTree then TypeTree(defn.ObjectType) else typedAheadType(tree.tpt)
22102210
val refineClsDef = desugar.refinedTypeToClass(tpt1, tree.refinements).withSpan(tree.span)
22112211
val refineCls = createSymbol(refineClsDef).asClass
22122212
val TypeDef(_, impl: Template) = typed(refineClsDef): @unchecked

compiler/test/dotc/pos-test-pickling.blacklist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,6 @@ parsercombinators-givens.scala
119119
parsercombinators-ctx-bounds.scala
120120
parsercombinators-this.scala
121121
parsercombinators-arrow.scala
122+
parsercombinators-new-syntax.scala
123+
hylolib
124+

tests/pos/hylolib/AnyCollection.scala

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//> using options -language:experimental.modularity -source future
12
package hylo
23

34
/** A type-erased collection.
@@ -14,12 +15,7 @@ final class AnyCollection[Element] private (
1415
object AnyCollection {
1516

1617
/** Creates an instance forwarding its operations to `base`. */
17-
def apply[Base: Collection as b](base: Base): AnyCollection[b.Element] =
18-
// NOTE: This evidence is redefined so the compiler won't report ambiguity between `intIsValue`
19-
// and `anyValueIsValue` when the method is called on a collection of `Int`s. None of these
20-
// choices is even correct! Note also that the ambiguity is suppressed if the constructor of
21-
// `AnyValue` is declared with a context bound rather than an implicit parameter.
22-
given b.Position is Value = b.Position
18+
def apply[Base: Collection](base: Base): AnyCollection[Base.Element] =
2319

2420
def start(): AnyValue =
2521
AnyValue(base.startPosition)
@@ -28,12 +24,12 @@ object AnyCollection {
2824
AnyValue(base.endPosition)
2925

3026
def after(p: AnyValue): AnyValue =
31-
AnyValue(base.positionAfter(p.unsafelyUnwrappedAs[b.Position]))
27+
AnyValue(base.positionAfter(p.unsafelyUnwrappedAs[Base.Position]))
3228

33-
def at(p: AnyValue): b.Element =
34-
base.at(p.unsafelyUnwrappedAs[b.Position])
29+
def at(p: AnyValue): Base.Element =
30+
base.at(p.unsafelyUnwrappedAs[Base.Position])
3531

36-
new AnyCollection[b.Element](
32+
new AnyCollection[Base.Element](
3733
_start = start,
3834
_end = end,
3935
_after = after,

tests/pos/hylolib/AnyValueTests.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//> using options -language:experimental.modularity -source future
2+
import hylo.*
3+
import hylo.given
4+
5+
class AnyValueTests extends munit.FunSuite:
6+
7+
test("eq"):
8+
val a = AnyValue(1)
9+
assert(a `eq` a)
10+
assert(!(a `neq` a))
11+
12+
val b = AnyValue(2)
13+
assert(!(a `eq` b))
14+
assert(a `neq` b)
15+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//> using options -language:experimental.modularity -source future
2+
import hylo.*
3+
import hylo.given
4+
5+
class CollectionTests extends munit.FunSuite:
6+
7+
test("isEmpty"):
8+
val empty = AnyCollection(HyArray[Int]())
9+
assert(empty.isEmpty)
10+
11+
val nonEmpty = AnyCollection(HyArray[Int](1, 2))
12+
assert(!nonEmpty.isEmpty)
13+
14+
test("count"):
15+
val a = AnyCollection(HyArray[Int](1, 2))
16+
assertEquals(a.count, 2)
17+
18+
test("isBefore"):
19+
val empty = AnyCollection(HyArray[Int]())
20+
assert(!empty.isBefore(empty.startPosition, empty.endPosition))
21+
22+
val nonEmpty = AnyCollection(HyArray[Int](1, 2))
23+
val p0 = nonEmpty.startPosition
24+
val p1 = nonEmpty.positionAfter(p0)
25+
val p2 = nonEmpty.positionAfter(p1)
26+
assert(nonEmpty.isBefore(p0, nonEmpty.endPosition))
27+
assert(nonEmpty.isBefore(p1, nonEmpty.endPosition))
28+
assert(!nonEmpty.isBefore(p2, nonEmpty.endPosition))
29+
30+
test("headAndTail"):
31+
val empty = AnyCollection(HyArray[Int]())
32+
assertEquals(empty.headAndTail, None)
33+
34+
val one = AnyCollection(HyArray[Int](1))
35+
val Some((h0, t0)) = one.headAndTail: @unchecked
36+
assert(h0 eq 1)
37+
assert(t0.isEmpty)
38+
39+
val two = AnyCollection(HyArray[Int](1, 2))
40+
val Some((h1, t1)) = two.headAndTail: @unchecked
41+
assertEquals(h1, 1)
42+
assertEquals(t1.count, 1)
43+
44+
test("reduce"):
45+
val empty = AnyCollection(HyArray[Int]())
46+
assertEquals(empty.reduce(0)((s, x) => s + x), 0)
47+
48+
val nonEmpty = AnyCollection(HyArray[Int](1, 2, 3))
49+
assertEquals(nonEmpty.reduce(0)((s, x) => s + x), 6)
50+
51+
test("forEach"):
52+
val empty = AnyCollection(HyArray[Int]())
53+
assert(empty.forEach((e) => false))
54+
55+
val nonEmpty = AnyCollection(HyArray[Int](1, 2, 3))
56+
var s = 0
57+
assert(nonEmpty.forEach((e) => { s += e; true }))
58+
assertEquals(s, 6)
59+
60+
s = 0
61+
assert(!nonEmpty.forEach((e) => { s += e; false }))
62+
assertEquals(s, 1)
63+
64+
test("elementsEqual"):
65+
val a = HyArray(1, 2)
66+
assert(a.elementsEqual(a))
67+
end CollectionTests

tests/pos/hylolib/Hasher.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//> using options -language:experimental.modularity -source future
12
package hylo
23

34
import scala.util.Random

tests/pos/hylolib/HyArray.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ final class HyArray[Element: Value as elementIsCValue](
5656
result._count += 1
5757
result
5858

59-
// NOTE: Can't refine `C.Element` without renaming the generic parameter of `HyArray`.
6059
/** Adds the contents of `source` at the end of the array. */
6160
def appendContents[C: Collection { type Element = HyArray.this.Element }](
6261
source: C, assumeUniqueness: Boolean = false

tests/pos/hylolib/HyArrayTests.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import hylo.*
2+
import hylo.given
3+
4+
class HyArrayTests extends munit.FunSuite:
5+
6+
test("reserveCapacity"):
7+
var a = HyArray[Int]()
8+
a = a.append(1)
9+
a = a.append(2)
10+
11+
a = a.reserveCapacity(10)
12+
assert(a.capacity >= 10)
13+
assertEquals(a.count, 2)
14+
assertEquals(a.at(0), 1)
15+
assertEquals(a.at(1), 2)
16+
17+
end HyArrayTests

tests/pos/hylolib/IntegersTests.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//> using options -language:experimental.modularity -source future
2+
import hylo.*
3+
import hylo.given
4+
5+
class IntegersTests extends munit.FunSuite:
6+
7+
test("Int.hashInto"):
8+
val x = Hasher.hash(42)
9+
val y = Hasher.hash(42)
10+
assertEquals(x, y)
11+
12+
val z = Hasher.hash(1337)
13+
assertNotEquals(x, z)
14+

tests/pos/hylolib/Test.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//> using options -language:experimental.modularity -source future
2+
import hylo.*
3+
import hylo.given
4+
5+
object munit:
6+
open class FunSuite:
7+
def test(name: String)(op: => Unit): Unit = op
8+
def assertEquals[T](x: T, y: T) = assert(x == y)
9+
def assertNotEquals[T](x: T, y: T) = assert(x != y)
10+
11+
@main def Test =
12+
CollectionTests()
13+
AnyValueTests()
14+
HyArrayTests()
15+
IntegersTests()
16+
println("done")

tests/pos/i13580.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//> using options -language:experimental.modularity -source future
2+
trait IntWidth:
3+
type Out
4+
given IntWidth:
5+
type Out = 155
6+
7+
trait IntCandidate:
8+
type Out
9+
given (using tracked val w: IntWidth) => IntCandidate:
10+
type Out = w.Out
11+
12+
val x = summon[IntCandidate]
13+
val xx = summon[x.Out =:= 155]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//> using options -language:experimental.modularity -source future
2+
import collection.mutable
3+
4+
/// A parser combinator.
5+
trait Combinator:
6+
7+
type Self
8+
type Input
9+
type Result
10+
11+
extension (self: Self)
12+
/// Parses and returns an element from input `in`.
13+
def parse(in: Input): Option[Result]
14+
end Combinator
15+
16+
case class Apply[C, E](action: C => Option[E])
17+
case class Combine[A, B](first: A, second: B)
18+
19+
given [I, R] => Apply[I, R] is Combinator:
20+
type Input = I
21+
type Result = R
22+
extension (self: Self)
23+
def parse(in: I): Option[R] = self.action(in)
24+
25+
given [A: Combinator, B: Combinator { type Input = A.Input }]
26+
=> Combine[A, B] is Combinator:
27+
type Input = A.Input
28+
type Result = (A.Result, B.Result)
29+
extension (self: Self)
30+
def parse(in: Input): Option[Result] = ???
31+
32+
extension [A] (buf: mutable.ListBuffer[A]) def popFirst() =
33+
if buf.isEmpty then None
34+
else try Some(buf.head) finally buf.remove(0)
35+
36+
@main def hello: Unit =
37+
val source = (0 to 10).toList
38+
val stream = source.to(mutable.ListBuffer)
39+
40+
val n = Apply[mutable.ListBuffer[Int], Int](s => s.popFirst())
41+
val m = Combine(n, n)
42+
43+
val r = m.parse(stream) // was error: type mismatch, found `mutable.ListBuffer[Int]`, required `?1.Input`
44+
val rc: Option[(Int, Int)] = r
45+

0 commit comments

Comments
 (0)