Skip to content

Commit

Permalink
Make some context bound evidence params tracked
Browse files Browse the repository at this point in the history
Make context bound evidence params tracked if they have types with abstract type members.
  • Loading branch information
odersky committed May 6, 2024
1 parent 0ad81e2 commit 196e730
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 21 deletions.
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ object Symbols extends SymUtils {
* With the given setup, all such calls will give implicit-not found errors
*/
final def symbol(implicit ev: DontUseSymbolOnSymbol): Nothing = unsupported("symbol")
type DontUseSymbolOnSymbol

final def source(using Context): SourceFile = {
def valid(src: SourceFile): SourceFile =
Expand Down Expand Up @@ -402,13 +401,12 @@ object Symbols extends SymUtils {
flags: FlagSet = this.flags,
info: Type = this.info,
privateWithin: Symbol = this.privateWithin,
coord: Coord = NoCoord, // Can be `= owner.coord` once we bootstrap
compUnitInfo: CompilationUnitInfo | Null = null // Can be `= owner.associatedFile` once we bootstrap
coord: Coord = NoCoord, // Can be `= owner.coord` once we have new default args
compUnitInfo: CompilationUnitInfo | Null = null // Can be `= owner.compilationUnitInfo` once we have new default args
): Symbol = {
val coord1 = if (coord == NoCoord) owner.coord else coord
val compilationUnitInfo1 = if (compilationUnitInfo == null) owner.compilationUnitInfo else compilationUnitInfo


if isClass then
newClassSymbol(owner, name.asTypeName, flags, _ => info, privateWithin, coord1, compilationUnitInfo1)
else
Expand Down Expand Up @@ -936,6 +934,8 @@ object Symbols extends SymUtils {
case (x: Symbol) :: _ if x.isType => Some(xs.asInstanceOf[List[TypeSymbol]])
case _ => None

type DontUseSymbolOnSymbol

// ----- Locating predefined symbols ----------------------------------------

def requiredPackage(path: PreName)(using Context): TermSymbol = {
Expand Down
30 changes: 30 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1885,6 +1885,28 @@ class Namer { typer: Typer =>
ddef.trailingParamss.foreach(completeParams)
val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
sym.setParamss(paramSymss)

/** We add `tracked` to context bound witnesses that have abstract type members */
def needsTracked(sym: Symbol, param: ValDef)(using Context) =
!sym.is(Tracked)
&& param.hasAttachment(ContextBoundParam)
&& sym.info.memberNames(abstractTypeNameFilter).nonEmpty

/** Set every context bound evidence parameter of a class to be tracked,
* provided it has a type that has an abstract type member. Reset private and local flags
* so that the parameter becomes a `val`.
*/
def setTracked(param: ValDef): Unit =
val sym = symbolOfTree(param)
sym.maybeOwner.maybeOwner.infoOrCompleter match
case info: TempClassInfo if needsTracked(sym, param) =>
typr.println(i"set tracked $param, $sym: ${sym.info} containing ${sym.info.memberNames(abstractTypeNameFilter).toList}")
for acc <- info.decls.lookupAll(sym.name) if acc.is(ParamAccessor) do
acc.resetFlag(PrivateLocal)
acc.setFlag(Tracked)
sym.setFlag(Tracked)
case _ =>

def wrapMethType(restpe: Type): Type =
instantiateDependent(restpe, paramSymss)
methodType(paramSymss, restpe, ddef.mods.is(JavaDefined))
Expand All @@ -1893,10 +1915,18 @@ class Namer { typer: Typer =>
wrapMethType(addParamRefinements(restpe, paramSymss))

if isConstructor then
if sym.isPrimaryConstructor && Feature.enabled(modularity) then
ddef.termParamss.foreach(_.foreach(setTracked))
// set result type tree to unit, but take the current class as result type of the symbol
typedAheadType(ddef.tpt, defn.UnitType)
wrapMethType(effectiveResultType(sym, paramSymss))
else if sym.isAllOf(Given | Method) && Feature.enabled(modularity) then
// set every context bound evidence parameter of a given companion method
// to be tracked, provided it has a type that has an abstract type member.
// Add refinements for all tracked parameters to the result type.
for params <- ddef.termParamss; param <- params do
val psym = symbolOfTree(param)
if needsTracked(psym, param) then psym.setFlag(Tracked)
valOrDefDefSig(ddef, sym, paramSymss, wrapRefinedMethType)
else
valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
Expand Down
4 changes: 2 additions & 2 deletions tests/pos/hylolib-cb/AnyCollection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class AnyCollection[Element] private (
object AnyCollection {

/** Creates an instance forwarding its operations to `base`. */
def apply[Base](using b: Collection[Base])(base: Base): AnyCollection[b.Element] =
def apply[Base: Collection as b](base: Base): AnyCollection[b.Element] =
// NOTE: This evidence is redefined so the compiler won't report ambiguity between `intIsValue`
// and `anyValueIsValue` when the method is called on a collection of `Int`s. None of these
// choices is even correct! Note also that the ambiguity is suppressed if the constructor of
Expand Down Expand Up @@ -42,7 +42,7 @@ object AnyCollection {

}

given anyCollectionIsCollection[T](using tIsValue: Value[T]): Collection[AnyCollection[T]] with {
given anyCollectionIsCollection[T: Value]: Collection[AnyCollection[T]] with {

type Element = T
type Position = AnyValue
Expand Down
9 changes: 4 additions & 5 deletions tests/pos/hylolib-cb/Collection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ trait Collection[Self] {

}

extension [Self](self: Self)(using s: Collection[Self]) {
extension [Self: Collection as s](self: Self) {

/** Returns the first element of `self` along with a slice containing the suffix after this
* element, or `None` if `self` is empty.
Expand Down Expand Up @@ -148,7 +148,7 @@ extension [Self](self: Self)(using s: Collection[Self]) {
* @complexity
* O(n) where n is the number of elements in `self`.
*/
def map[T](using Value[T])(transform: (s.Element) => T): HyArray[T] =
def map[T: Value](transform: (s.Element) => T): HyArray[T] =
self.reduce(
HyArray[T](),
(r, e) => r.append(transform(e), assumeUniqueness = true)
Expand Down Expand Up @@ -257,9 +257,8 @@ extension [Self](self: Self)(using s: Collection[Self]) {

}

extension [Self](self: Self)(using
s: Collection[Self],
e: Value[s.Element]
extension [Self: Collection as s](self: Self)(using
Value[s.Element]
) {

/** Returns `true` if `self` contains the same elements as `other`, in the same order. */
Expand Down
11 changes: 5 additions & 6 deletions tests/pos/hylolib-cb/HyArray.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//> using options -language:experimental.modularity -source future
package hylo

import java.util.Arrays
import scala.collection.mutable

/** An ordered, random-access collection. */
final class HyArray[Element] private (using
elementIsValue: Value[Element]
)(
final class HyArray[Element: Value as elementIsCValue](
private var _storage: scala.Array[AnyRef | Null] | Null,
private var _count: Int // NOTE: where do I document private fields
) {
Expand Down Expand Up @@ -155,14 +154,14 @@ final class HyArray[Element] private (using
object HyArray {

/** Creates an array with the given `elements`. */
def apply[T](using t: Value[T])(elements: T*): HyArray[T] =
def apply[T: Value](elements: T*): HyArray[T] =
var a = new HyArray[T](null, 0)
for (e <- elements) a = a.append(e, assumeUniqueness = true)
a

}

given hyArrayIsValue[T](using tIsValue: Value[T]): Value[HyArray[T]] with {
given [T: Value] => Value[HyArray[T]] with {

extension (self: HyArray[T]) {

Expand All @@ -179,7 +178,7 @@ given hyArrayIsValue[T](using tIsValue: Value[T]): Value[HyArray[T]] with {

}

given hyArrayIsCollection[T](using tIsValue: Value[T]): Collection[HyArray[T]] with {
given [T: Value] => Collection[HyArray[T]] with {

type Element = T
type Position = Int
Expand Down
6 changes: 2 additions & 4 deletions tests/pos/hylolib-cb/Slice.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package hylo

/** A view into a collection. */
final class Slice[Base](using
val b: Collection[Base]
)(
final class Slice[Base: Collection as b](
val base: Base,
val bounds: Range[b.Position]
) {
Expand All @@ -26,7 +24,7 @@ final class Slice[Base](using

}

given sliceIsCollection[T](using c: Collection[T]): Collection[Slice[T]] with {
given sliceIsCollection[T: Collection as c]: Collection[Slice[T]] with {

type Element = c.Element
type Position = c.Position
Expand Down

0 comments on commit 196e730

Please sign in to comment.