diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 7f6f13585efd..a91e29711e7c 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -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 = @@ -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 @@ -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 = { diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 22a12ed0f468..85678b9685f7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -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)) @@ -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) diff --git a/tests/pos/hylolib-cb/AnyCollection.scala b/tests/pos/hylolib-cb/AnyCollection.scala index 1a44344d0e51..50f4313e46ce 100644 --- a/tests/pos/hylolib-cb/AnyCollection.scala +++ b/tests/pos/hylolib-cb/AnyCollection.scala @@ -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 @@ -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 diff --git a/tests/pos/hylolib-cb/Collection.scala b/tests/pos/hylolib-cb/Collection.scala index 073a99cdd16b..2fc04f02b9ac 100644 --- a/tests/pos/hylolib-cb/Collection.scala +++ b/tests/pos/hylolib-cb/Collection.scala @@ -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. @@ -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) @@ -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. */ diff --git a/tests/pos/hylolib-cb/HyArray.scala b/tests/pos/hylolib-cb/HyArray.scala index 9347f7eb12cc..0fff45e744ec 100644 --- a/tests/pos/hylolib-cb/HyArray.scala +++ b/tests/pos/hylolib-cb/HyArray.scala @@ -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 ) { @@ -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]) { @@ -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 diff --git a/tests/pos/hylolib-cb/Slice.scala b/tests/pos/hylolib-cb/Slice.scala index 2289ac2a085b..b577ceeb3739 100644 --- a/tests/pos/hylolib-cb/Slice.scala +++ b/tests/pos/hylolib-cb/Slice.scala @@ -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] ) { @@ -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