@effekt-lang/effekt 0.78.0 → 0.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -80,19 +80,13 @@ def get[K, V](m: Map[K, V], k: K): Option[V] = internal::get(m.tree, m.compare,
80
80
  ///
81
81
  /// O(log N)
82
82
  def getOrElse[K, V](m: Map[K, V], k: K) { default: => V }: V =
83
- internal::get(m.tree, m.compare, k) match {
84
- case None() => default()
85
- case Some(v) => v
86
- }
83
+ internal::getOrElse(m.tree, m.compare, k) {default}
87
84
 
88
85
  /// Check if map `m` contains a key `k`.
89
86
  ///
90
87
  /// O(log N)
91
88
  def contains[K, V](m: Map[K, V], k: K): Bool =
92
- internal::get(m.tree, m.compare, k) match {
93
- case None() => false
94
- case Some(_) => true
95
- }
89
+ internal::contains(m.tree, m.compare, k)
96
90
 
97
91
  /// Get minimum in the map `m`.
98
92
  ///
@@ -354,15 +348,10 @@ def collect[K, V](?compare: (K, K) => Ordering at {}) { stream: () => Unit / emi
354
348
  namespace returning {
355
349
  /// Collects `(key, value)` pairs from a push stream producer `stream` into a new `map`,
356
350
  /// using the provided `compare` function, returning the result of the producer as well as the collected map.
357
- def collect[K, V, R](?compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) =
358
- var map = map::empty[K, V](compare)
359
- val r = try {
360
- stream()
361
- } with emit[(K, V)] { case (k, v) =>
362
- map = map.put(k, v)
363
- resume(())
364
- }
365
- (r, map)
351
+ def collect[K, V, R](?compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) = {
352
+ val (r, tree) = internal::collect[K, V, R](compare) {stream}
353
+ (r, Map(tree, compare))
354
+ }
366
355
  }
367
356
 
368
357
  // Internal tree representation
@@ -417,6 +406,33 @@ namespace internal {
417
406
  case Bin(size, _, _, _, _) => size
418
407
  }
419
408
 
409
+ /// Look up `k` in the tree `m`, handing the value it is bound to to `found`,
410
+ /// or running `missing` if there is none.
411
+ ///
412
+ /// O(log N)
413
+ def getWith[K, V, R](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K) { found: V => R } { missing: => R }: R =
414
+ m match {
415
+ case Tip() => missing()
416
+ case Bin(_, k2, v, l, r) =>
417
+ compare(k, k2) match {
418
+ case Less() => getWith(l, compare, k) {found} {missing}
419
+ case Greater() => getWith(r, compare, k) {found} {missing}
420
+ case Equal() => found(v)
421
+ }
422
+ }
423
+
424
+ /// Whether the tree `m` binds the key `k`.
425
+ ///
426
+ /// O(log N)
427
+ def contains[K, V](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K): Bool =
428
+ getWith(m, compare, k) { _v => true } { false }
429
+
430
+ /// The value bound to `k` in the tree `m`, or `default` if there is none.
431
+ ///
432
+ /// O(log N)
433
+ def getOrElse[K, V](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K) { default: => V }: V =
434
+ getWith(m, compare, k) { v => v } {default}
435
+
420
436
  /// Insert a new key `k` and value `v` into the tree `m`.
421
437
  /// If the key `k` is already present in `m`, its associated value is replaced with `v`.
422
438
  ///
@@ -451,15 +467,7 @@ namespace internal {
451
467
  ///
452
468
  /// O(log N)
453
469
  def get[K, V](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K): Option[V] =
454
- m match {
455
- case Tip() => None()
456
- case Bin(size, k2, v, l, r) =>
457
- compare(k, k2) match {
458
- case Less() => get(l, compare, k)
459
- case Greater() => get(r, compare, k)
460
- case Equal() => Some(v)
461
- }
462
- }
470
+ getWith(m, compare, k) { v => Some(v) } { None() }
463
471
 
464
472
  /// Get minimum in the tree `m`.
465
473
  ///
@@ -600,98 +608,184 @@ namespace internal {
600
608
  go(m)
601
609
  }
602
610
 
611
+ /// A balanced subtree waiting to be joined, and the key separating it from the pairs collected after it.
612
+ ///
613
+ /// A list of these is the *right* spine of the tree being built.
614
+ /// Their sizes strictly increase towards the back, so the list is the digits of a binary counter.
615
+ record Waiting[K, V](size: Int, key: K, value: V, tree: Tree[K, V])
616
+
617
+ /// Collect `(key, value)` pairs from a push stream producer `stream` into a tree,
618
+ /// returning the result of the producer as well.
619
+ /// Consider using `map::fromList` if you know the full list.
620
+ ///
621
+ /// O(N) if the stream is sorted by key (in _either_ direction),
622
+ /// O(N log N) otherwise
623
+ def collect[K, V, R](compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Tree[K, V]) = {
624
+ // Note that `fromList` is always better since it knows the whole list of pairs in advance,
625
+ // whereas we have to be streaming here. Otherwise the functions are very similar...
626
+
627
+ // The lowest digit of the binary counter is a lone pair, kept as the leaf it will one day become. :)
628
+ var lowest: Tree[K, V] = Tip()
629
+ var spine: List[Waiting[K, V]] = Nil()
630
+ var tree = Tip()
631
+ // which way the current run is going; is `Equal` once a monotone run is over
632
+ var direction: Ordering = Less()
633
+
634
+ // How the currently collected pair compares with the one collected last.
635
+ def compareLast(k: K): Ordering =
636
+ lowest match {
637
+ case Bin(_, previous, _, _, _) => compare(previous, k)
638
+ case Tip() => spine match {
639
+ case Nil() => Less()
640
+ case Cons(Waiting(_, previous, _, _), _) => compare(previous, k)
641
+ }
642
+ }
643
+
644
+ // Give the pair collected last a new value, overwriting the existing one.
645
+ def rebind(v: V): Unit =
646
+ lowest match {
647
+ case Bin(_, k, _, _, _) =>
648
+ lowest = singleton(k, v)
649
+ case Tip() => spine match {
650
+ case Nil() => ()
651
+ case Cons(Waiting(size, k, _, tree), more) =>
652
+ spine = Cons(Waiting(size, k, v, tree), more)
653
+ }
654
+ }
655
+
656
+ // Increment the binary counter: carry while the next subtree has the same size.
657
+ def extend(k: K, v: V): Unit = {
658
+ def carry(size: Int, subtree: Tree[K, V], rest: List[Waiting[K, V]]): List[Waiting[K, V]] =
659
+ rest match {
660
+ case Nil() => [Waiting(size, k, v, subtree)]
661
+ case Cons(Waiting(s, k2, v2, t), more) =>
662
+ if (s == size) {
663
+ val merged = if (direction is Greater()) bin(k2, v2, subtree, t) else bin(k2, v2, t, subtree)
664
+ carry(2 * size + 1, merged, more)
665
+ } else {
666
+ Cons(Waiting(size, k, v, subtree), rest)
667
+ }
668
+ }
669
+
670
+ lowest match {
671
+ case Tip() => lowest = singleton(k, v)
672
+ case Bin(_, _, _, _, _) =>
673
+ val leaf = lowest
674
+ lowest = Tip()
675
+ spine = carry(1, leaf, spine)
676
+ }
677
+ }
678
+
679
+ def joinSpineWith(spine: List[Waiting[K, V]], whole: Tree[K, V]): Tree[K, V] =
680
+ spine match {
681
+ case Nil() => whole
682
+ case Cons(Waiting(_, k, v, subtree), more) =>
683
+ val joined = if (direction is Greater()) link(k, v, whole, subtree) else link(k, v, subtree, whole)
684
+ more.joinSpineWith(joined)
685
+ }
686
+
687
+ val result = try {
688
+ stream()
689
+ } with emit[(K, V)] { case (k, v) =>
690
+ // as long as the keys all keep going the same way, we can build a tree in O(N) time
691
+ direction match {
692
+ // the run is over, so we have to insert each new pair without a shortcut
693
+ case Equal() => tree = tree.put(compare, k, v)
694
+ case _ =>
695
+ (compareLast(k), direction) match {
696
+ case (Equal(), _) => rebind(v)
697
+ case (Less(), Less()) => extend(k, v)
698
+ case (Greater(), Greater()) => extend(k, v)
699
+ case (ordering, _) =>
700
+ // the new key goes against the run:
701
+ if (spine is Nil()) {
702
+ // - if it's the first pair, we just set the direction
703
+ direction = ordering
704
+ extend(k, v)
705
+ } else {
706
+ // - if it's not the first pair, we have to join up the run and use the slow path
707
+ tree = spine.joinSpineWith(lowest).put(compare, k, v)
708
+ direction = Equal()
709
+ }
710
+ }
711
+ }
712
+
713
+ resume(())
714
+ }
715
+
716
+ (result, if (direction is Equal()) tree else spine.joinSpineWith(lowest))
717
+ }
718
+
603
719
  /// Create a tree from a list of (key, value) pairs.
604
720
  /// If the list contains more than one value for the same key,
605
721
  /// only the last value is used in the tree.
606
722
  ///
607
- /// O(N) if the list is sorted by key,
723
+ /// O(N) if the list is sorted by key (in _either_ direction),
608
724
  /// O(N log N) otherwise
609
- def fromList[K, V](pairs: List[(K, V)], compare: (K, K) => Ordering at {}): Tree[K, V] = {
725
+ def fromList[K, V](pairs: List[(K, V)], compare: (K, K) => Ordering at {}): Tree[K, V] =
610
726
  pairs match {
611
727
  case Nil() => Tip()
612
728
  case Cons((k, v), Nil()) => singleton(k, v)
613
- case Cons((k, v), rest) =>
614
- // TODO: this function should really, **really** get inlined!
615
- def notOrdered(k: K, pairs: List[(K, V)]) = {
616
- pairs match {
617
- case Nil() => false
618
- case Cons((k2, _), _) => // k >= k2
619
- compare(k, k2) match {
620
- case Less() => false
621
- case Greater() => true
622
- case Equal() => true
729
+ case Cons(_, _) =>
730
+ // the first pair not yet taken, and whether the run repeated a key
731
+ var rest = pairs
732
+ var repeated = false
733
+ // which way the current run is going; is `Equal` once a monotone run is over
734
+ var direction: Ordering = Equal()
735
+
736
+ // How many distinct keys the non-decreasing run at the front of `ps` holds.
737
+ def runLength(ps: List[(K, V)], count: Int): Int =
738
+ ps match {
739
+ case Nil() => count
740
+ case Cons((k, _), tail) => tail match { // note: tail is effectivelly an @-pattern!
741
+ case Nil() => count + 1
742
+ case Cons((next, _), _) => (compare(k, next), direction) match {
743
+ case (Less() , Less() ) => runLength(tail, count + 1)
744
+ case (Greater(), Greater()) => runLength(tail, count + 1)
745
+ case (Equal(), _) => repeated = true; runLength(tail, count)
746
+
747
+ // the first comparison that is not `Equal` settles which way we go
748
+ case (ordering, Equal()) => direction = ordering; runLength(tail, count + 1)
749
+ case _ => count + 1
623
750
  }
751
+ }
624
752
  }
625
- }
626
753
 
627
- // Naive insertion, used for the worst-case scenario when the list is not sorted by key
628
- def insertMany(m: Tree[K, V], pairs: List[(K, V)]) = {
629
- var treeSoFar = m
630
- pairs.foreach { case (k, v) =>
631
- treeSoFar = treeSoFar.put(compare, k, v)
754
+ // Advance `rest` past any repeats of `k`, giving back the last binding of it.
755
+ def lastBinding(k: K, v: V): V =
756
+ if (rest is Cons((next, value), tail) and compare(k, next) is Equal()) {
757
+ rest = tail
758
+ lastBinding(k, value)
759
+ } else {
760
+ v
632
761
  }
633
- treeSoFar
634
- }
635
762
 
636
- // Returns a triple `(tree, xs, ys)`
637
- //
638
- // Invariant: At least one of `xs`, `ys` is empty.
639
- // Moreover, if `ys` is nonempty, its keys are **not** ordered!
640
- // Otherwise, all of the seen keys have been ordered so far.
641
- //
642
- // TODO: Possibly use a better type to encode the invariant?
643
- def create(level: Int, pairs: List[(K, V)]): (Tree[K, V], List[(K, V)], List[(K, V)]) = {
644
- pairs match {
645
- case Nil() => (Tip(), [], [])
646
- case Cons((k, v), rest) =>
647
- if (level == 1) {
648
- val one = singleton(k, v)
649
- if (notOrdered(k, rest)) {
650
- (one, [], rest)
651
- } else {
652
- (one, rest, [])
653
- }
654
- } else {
655
- val res = create(level.bitwiseShr(1), pairs)
656
- res match {
657
- case (_, Nil(), _) => res
658
- case (l, Cons((k2, v2), Nil()), zs) => (l.putMax(k2, v2), [], zs)
659
- case (l, Cons((k2, v2), rest2), _) =>
660
- // @-pattern
661
- val xs = Cons((k2, v2), rest2)
662
-
663
- if (notOrdered(k2, rest2)) { (l, [], xs) }
664
- else {
665
- val (r, zs, ws) = create(level.bitwiseShr(1), rest2);
666
- (link(k2, v2, l, r), zs, ws)
667
- }
668
- }
669
- }
763
+ // Shape `count` distinct keys from `rest` into a balanced tree, leaving `rest` on the first pair not taken.
764
+ // The order is established already, so knowing the size lays the tree out from the root down, one node per key.
765
+ def fromSorted(count: Int): Tree[K, V] =
766
+ if (count <= 0) Tip() else {
767
+ val half = (count - 1) / 2
768
+ val front = half.fromSorted
769
+ rest match {
770
+ case Nil() => <{ "fromList: fewer pairs than counted" }>
771
+ case Cons((k, v), tail) =>
772
+ rest = tail
773
+ val value = if (repeated) lastBinding(k, v) else v
774
+ val back = (count - 1 - half).fromSorted
775
+ if (direction is Greater()) bin(k, value, back, front) else bin(k, value, front, back)
776
+ }
670
777
  }
671
- }
672
778
 
673
- def go(level: Int, m: Tree[K, V], pairs: List[(K, V)]): Tree[K, V] = {
674
- pairs match {
779
+ // Whatever is left, once the run has stopped, goes through `put`.
780
+ def insertMany(m: Tree[K, V], ps: List[(K, V)]): Tree[K, V] =
781
+ ps match {
675
782
  case Nil() => m
676
- case Cons((k, v), Nil()) => m.putMax(k, v)
677
- case Cons((k, v), rest) =>
678
- if (notOrdered(k, rest)) { insertMany(m, pairs) }
679
- else {
680
- val l = m; // m is the left subtree here
681
- val cr = create(level, rest)
682
- cr match {
683
- case (r, xs, Nil()) => go(level.bitwiseShl(1), link(k, v, l, r), xs)
684
- case (r, Nil(), ys) => insertMany(link(k, v, l, r), ys)
685
- case _ => <{ "create: go: cannot happen, invariant broken!" }>
686
- }
687
- }
783
+ case Cons((k, v), tail) => m.put(compare, k, v).insertMany(tail)
688
784
  }
689
- }
690
785
 
691
- if (notOrdered(k, rest)) { insertMany(singleton(k, v), rest) }
692
- else { go(1, singleton(k, v), rest) }
786
+ val sorted = runLength(pairs, 0).fromSorted
787
+ sorted.insertMany(rest)
693
788
  }
694
- }
695
789
 
696
790
  /// Remove a key `k` from a tree `m`.
697
791
  /// If `k` is not in `m`, `m` is returned.
@@ -1053,4 +1147,4 @@ namespace internal {
1053
1147
 
1054
1148
  "[" ++ res ++ "]"
1055
1149
  }
1056
- }
1150
+ }
@@ -4,7 +4,8 @@ import array
4
4
  extern def exit(errorCode: Int) at io: Nothing =
5
5
  js "(function() { process.exit(${errorCode}) })()"
6
6
  llvm """
7
- call void @exit(i64 ${errorCode})
7
+ %exitCode = trunc i64 ${errorCode} to i32
8
+ call void @exit(i32 %exitCode)
8
9
  ret %Pos zeroinitializer
9
10
  """
10
11
  chez "(exit ${errorCode})"
@@ -107,6 +108,6 @@ extern def spawn(cmd: String, args: Array[String], options: SpawnOptions) at asy
107
108
  return p;
108
109
  })"""
109
110
  llvm """
110
- call void @c_spawn(%Pos ${cmd}, %Pos ${args}, %Pos ${options}, %Stack %stack)
111
+ notail call void @c_spawn(%Pos ${cmd}, %Pos ${args}, %Pos ${options}, %Stack %stack)
111
112
  ret void
112
113
  """
@@ -114,11 +114,24 @@ def randomInt32s(): Unit / {emit[Int], random} =
114
114
 
115
115
  /// `max` is _inclusive_!
116
116
  def randomInt(min: Int, max: Int): Int / random = {
117
+ // How many bytes it takes to represent `range` distinct values.
118
+ // Each bound is a power of two, so it's exact even as a JS 'number'.
119
+ def bytesFor(range: Int): Int =
120
+ if (range <= 1) 0
121
+ else if (range <= 256) 1
122
+ else if (range <= 65536) 2
123
+ else if (range <= 16777216) 3
124
+ else if (range <= 4294967296) 4
125
+ else if (range <= 1099511627776) 5
126
+ else if (range <= 281474976710656) 6
127
+ else if (range <= 72057594037927936) 7
128
+ else 8
129
+
117
130
  if (min > max) {
118
131
  randomInt(max, min)
119
132
  } else {
120
133
  val range = max - min + 1
121
- val bytesNeeded = (log(range.toDouble) / log(256.0)).ceil
134
+ val bytesNeeded = bytesFor(range)
122
135
 
123
136
  var result = 0
124
137
  repeat(bytesNeeded) {
@@ -79,22 +79,19 @@ def toMap[K, V](keys: Set[K]) { valueOf: K => V }: Map[K, V] = {
79
79
 
80
80
  /// Create a set from a given list and a pure, first-class comparison function.
81
81
  ///
82
- /// O(N log N)
83
82
  /// O(N) if the list is sorted
84
- def fromList[A](list: List[A], ?compare: (A, A) => Ordering at {}): Set[A] = {
85
- val tree: internal::Tree[A, Unit] = internal::fromList(list.map { k => (k, ()) }, compare)
86
- Set(tree, compare)
87
- }
83
+ /// O(N log N)
84
+ def fromList[A](list: List[A], ?compare: (A, A) => Ordering at {}): Set[A] =
85
+ set::collect(compare) { list.each }
88
86
 
89
87
  /// Create a set from a given list with a generic comparison function.
90
88
  /// Works only on the JavaScript backends!
91
89
  ///
92
- /// O(N log N)
93
90
  /// O(N) if the list is sorted
91
+ /// O(N log N)
94
92
  def fromListGeneric[A](list: List[A]): Set[A] = {
95
93
  val compare: (A, A) => Ordering at {} = box { (left, right) => genericCompare(left, right) }
96
- val tree: internal::Tree[A, Unit] = internal::fromList(list.map { k => (k, ()) }, compare)
97
- Set(tree, compare)
94
+ set::collect(compare) { list.each }
98
95
  }
99
96
 
100
97
  /// Traverse all elements in order, running the function `action` on each element.
@@ -150,10 +147,7 @@ def any[A](s: Set[A]) { predicate: A => Bool }: Bool = {
150
147
  ///
151
148
  /// O(log N)
152
149
  def contains[A](s: Set[A], a: A): Bool =
153
- internal::get(s.tree, s.compare, a) match {
154
- case None() => false
155
- case Some(v) => true
156
- }
150
+ internal::contains(s.tree, s.compare, a)
157
151
 
158
152
 
159
153
  /// Check if set `s1` is a subset of set `s2`.
@@ -260,13 +254,9 @@ namespace returning {
260
254
  /// Collects elements emitted by a push stream producer `stream` into a new set
261
255
  /// using provided `compare` function, returning the result of the producer as well as the collected set.
262
256
  def collect[A, R](?compare: (A, A) => Ordering at {}) { stream: () => R / emit[A] }: (R, Set[A]) = {
263
- var set = set::empty(compare)
264
- val r = try {
265
- stream()
266
- } with emit[A] { (v) =>
267
- set = set.insert(v)
268
- resume(())
257
+ val (r, tree) = internal::collect[A, Unit, R](compare) {
258
+ stream::returning::for[A, R] {stream} { (v: A) => do emit((v, ())) }
269
259
  }
270
- (r, set)
260
+ (r, Set(tree, compare))
271
261
  }
272
262
  }
@@ -77,7 +77,7 @@ struct Pos c_bytearray_construct(const uint64_t n, const uint8_t *data) {
77
77
 
78
78
  struct Pos c_bytearray_from_nullterminated_string(const char *data) {
79
79
  uint64_t n = 0;
80
- while (data[++n]);
80
+ while (data[n]) n++;
81
81
 
82
82
  return c_bytearray_construct(n, (uint8_t*)data);
83
83
  }
@@ -101,7 +101,7 @@ declare ptr @malloc(i64)
101
101
  declare void @free(ptr)
102
102
  declare ptr @realloc(ptr, i64)
103
103
  declare noalias ptr @calloc(i64, i64)
104
- declare void @memcpy(ptr, ptr, i64)
104
+ declare ptr @memcpy(ptr, ptr, i64)
105
105
  declare i64 @llvm.ctlz.i64 (i64 , i1)
106
106
  declare i64 @llvm.fshr.i64(i64, i64, i64)
107
107
  declare double @llvm.sqrt.f64(double)
@@ -117,8 +117,7 @@ declare double @log1p(double)
117
117
  ; Intrinsic versions of the following two only added in LLVM 19
118
118
  declare double @atan(double)
119
119
  declare double @tan(double)
120
- declare void @print(i64)
121
- declare void @exit(i64)
120
+ declare void @exit(i32)
122
121
  declare void @llvm.assume(i1)
123
122
 
124
123
 
@@ -162,7 +161,7 @@ define private void @shareObject(%Object %object) alwaysinline {
162
161
 
163
162
  next:
164
163
  %objectReferenceCount = getelementptr %Header, ptr %object, i64 0, i32 0
165
- %referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24
164
+ %referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24, !range !41
166
165
  %referenceCount.1 = add %ReferenceCount %referenceCount, 1
167
166
  store %ReferenceCount %referenceCount.1, ptr %objectReferenceCount, !alias.scope !14, !noalias !24
168
167
  br label %done
@@ -189,7 +188,7 @@ define private void @eraseObject(%Object %object) alwaysinline {
189
188
 
190
189
  next:
191
190
  %objectReferenceCount = getelementptr %Header, ptr %object, i64 0, i32 0
192
- %referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24
191
+ %referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24, !range !41
193
192
  switch %ReferenceCount %referenceCount, label %decr [%ReferenceCount 0, label %free]
194
193
 
195
194
  decr:
@@ -334,10 +333,8 @@ realloc:
334
333
 
335
334
  define private %StackPointer @stackAllocate(%Stack %stack, i64 %n) alwaysinline {
336
335
  %stackPointer_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1
337
- %limit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
338
336
 
339
337
  %currentStackPointer = load %StackPointer, ptr %stackPointer_pointer, !alias.scope !11, !noalias !21
340
- %limit = load %Limit, ptr %limit_pointer, !alias.scope !11, !noalias !21
341
338
  %nextStackPointer = getelementptr i8, %StackPointer %currentStackPointer, i64 %n
342
339
 
343
340
  store %StackPointer %nextStackPointer, ptr %stackPointer_pointer, !alias.scope !11, !noalias !21
@@ -486,7 +483,7 @@ define private {%Resumption, %Stack} @shift(%Stack %stack, %Prompt %prompt) {
486
483
 
487
484
  define private void @erasePrompt(%Prompt %prompt) alwaysinline {
488
485
  %referenceCount_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 0
489
- %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23
486
+ %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23, !range !41
490
487
  switch %ReferenceCount %referenceCount, label %decrement [%ReferenceCount 0, label %free]
491
488
 
492
489
  decrement:
@@ -501,7 +498,7 @@ free:
501
498
 
502
499
  define private void @sharePrompt(%Prompt %prompt) alwaysinline {
503
500
  %referenceCount_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 0
504
- %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23
501
+ %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23, !range !41
505
502
  %newReferenceCount = add %ReferenceCount %referenceCount, 1
506
503
  store %ReferenceCount %newReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23
507
504
  ret void
@@ -544,7 +541,7 @@ define private %Stack @copyStack(%Stack %stack) alwaysinline {
544
541
  %newStackPointer = getelementptr i8, %Stack %newStack, i64 %used
545
542
  %newLimit = getelementptr i8, %Stack %newStack, i64 %size
546
543
 
547
- call void @memcpy(ptr %newStack, ptr %stack, i64 %used)
544
+ %copied = call ptr @memcpy(ptr %newStack, ptr %stack, i64 %used)
548
545
 
549
546
  %newStackPointer_pointer = getelementptr %StackValue, %Stack %newStack, i64 0, i32 1
550
547
  %newLimit_pointer = getelementptr %StackValue, %Stack %newStack, i64 0, i32 2
@@ -569,7 +566,7 @@ define private %Resumption @uniqueStack(%Resumption %resumption) alwaysinline {
569
566
 
570
567
  entry:
571
568
  %referenceCount_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 0
572
- %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
569
+ %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21, !range !41
573
570
  switch %ReferenceCount %referenceCount, label %copy [%ReferenceCount 0, label %done]
574
571
 
575
572
  done:
@@ -613,7 +610,7 @@ stop:
613
610
 
614
611
  define void @shareResumption(%Resumption %resumption) alwaysinline {
615
612
  %referenceCount_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 0
616
- %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
613
+ %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21, !range !41
617
614
  %referenceCount.1 = add %ReferenceCount %referenceCount, 1
618
615
  store %ReferenceCount %referenceCount.1, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
619
616
  ret void
@@ -621,7 +618,7 @@ define void @shareResumption(%Resumption %resumption) alwaysinline {
621
618
 
622
619
  define void @eraseResumption(%Resumption %resumption) alwaysinline {
623
620
  %referenceCount_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 0
624
- %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
621
+ %referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21, !range !41
625
622
  switch %ReferenceCount %referenceCount, label %decr [%ReferenceCount 0, label %free]
626
623
 
627
624
  decr:
@@ -914,4 +911,7 @@ define ccc %CObject @coercePosObj(%Pos %input) {
914
911
  !22 = !{!1, !3, !4, !5} ; not stackPointer
915
912
  !23 = !{!1, !2, !4, !5} ; not prompt
916
913
  !24 = !{!1, !2, !3, !5} ; not object
917
- !25 = !{!1, !2, !3, !4 } ; not vtable
914
+ !25 = !{!1, !2, !3, !4 } ; not vtable
915
+
916
+ ; Ranges
917
+ !41 = !{i64 0, i64 9223372036854775807} ; positive i64