Skip to content

Commit 41a5126

Browse files
committed
A PoC for infering tracked with one working case
1 parent dd37f07 commit 41a5126

File tree

2 files changed

+79
-5
lines changed

2 files changed

+79
-5
lines changed

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

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,8 @@ class Namer { typer: Typer =>
15451545
case completer: Completer => completer.indexConstructor(constr, constrSym)
15461546
case _ =>
15471547

1548+
// constrSym.info = typeSig(constrSym)
1549+
15481550
tempInfo = denot.asClass.classInfo.integrateOpaqueMembers.asInstanceOf[TempClassInfo]
15491551
denot.info = savedInfo
15501552
}
@@ -1646,14 +1648,17 @@ class Namer { typer: Typer =>
16461648
* as an attachment on the ClassDef tree.
16471649
*/
16481650
def enterParentRefinementSyms(refinements: List[(Name, Type)]) =
1651+
println(s"For class $cls, entering parent refinements: $refinements")
16491652
val refinedSyms = mutable.ListBuffer[Symbol]()
16501653
for (name, tp) <- refinements do
16511654
if decls.lookupEntry(name) == null then
16521655
val flags = tp match
16531656
case tp: MethodOrPoly => Method | Synthetic | Deferred | Tracked
16541657
case _ if name.isTermName => Synthetic | Deferred | Tracked
16551658
case _ => Synthetic | Deferred
1656-
refinedSyms += newSymbol(cls, name, flags, tp, coord = original.rhs.span.startPos).entered
1659+
val s = newSymbol(cls, name, flags, tp, coord = original.rhs.span.startPos).entered
1660+
refinedSyms += s
1661+
println(s" entered $s")
16571662
if refinedSyms.nonEmpty then
16581663
typr.println(i"parent refinement symbols: ${refinedSyms.toList}")
16591664
original.pushAttachment(ParentRefinements, refinedSyms.toList)
@@ -1695,6 +1700,7 @@ class Namer { typer: Typer =>
16951700
end addUsingTraits
16961701

16971702
completeConstructor(denot)
1703+
val constrSym = symbolOfTree(constr)
16981704
denot.info = tempInfo.nn
16991705

17001706
val parentTypes = defn.adjustForTuple(cls, cls.typeParams,
@@ -1928,7 +1934,7 @@ class Namer { typer: Typer =>
19281934
val mt = wrapMethType(effectiveResultType(sym, paramSymss))
19291935
if sym.isPrimaryConstructor then checkCaseClassParamDependencies(mt, sym.owner)
19301936
mt
1931-
else if sym.isAllOf(Given | Method) && Feature.enabled(modularity) then
1937+
else if Feature.enabled(modularity) then
19321938
// set every context bound evidence parameter of a given companion method
19331939
// to be tracked, provided it has a type that has an abstract type member.
19341940
// Add refinements for all tracked parameters to the result type.
@@ -1986,14 +1992,60 @@ class Namer { typer: Typer =>
19861992
cls.srcPos)
19871993
case _ =>
19881994

1989-
/** Under x.modularity, we add `tracked` to context bound witnesses
1990-
* that have abstract type members
1995+
/** Try to infer if the parameter needs a `tracked` modifier
19911996
*/
19921997
def needsTracked(sym: Symbol, param: ValDef)(using Context) =
19931998
!sym.is(Tracked)
1994-
&& param.hasAttachment(ContextBoundParam)
1999+
&& (
2000+
isContextBoundWitnessWithAbstractMembers(sym, param)
2001+
|| isReferencedInPublicSignatures(sym)
2002+
// || isPassedToTrackedParentParameter(sym, param)
2003+
)
2004+
2005+
/** Under x.modularity, we add `tracked` to context bound witnesses
2006+
* that have abstract type members
2007+
*/
2008+
def isContextBoundWitnessWithAbstractMembers(sym: Symbol, param: ValDef)(using Context): Boolean =
2009+
param.hasAttachment(ContextBoundParam)
19952010
&& sym.info.memberNames(abstractTypeNameFilter).nonEmpty
19962011

2012+
/** Under x.modularity, we add `tracked` to term parameters whose types are referenced
2013+
* in public signatures of the defining class
2014+
*/
2015+
def isReferencedInPublicSignatures(sym: Symbol)(using Context): Boolean =
2016+
val owner = sym.maybeOwner.maybeOwner
2017+
val accessorSyms = maybeParamAccessors(owner, sym)
2018+
def checkOwnerMemberSignatures(owner: Symbol): Boolean =
2019+
owner.infoOrCompleter match
2020+
case info: ClassInfo =>
2021+
info.decls.filter(d => !d.isConstructor).exists(d => tpeContainsSymbolRef(d.info, accessorSyms))
2022+
case _ => false
2023+
checkOwnerMemberSignatures(owner)
2024+
2025+
def isPassedToTrackedParentParameter(sym: Symbol, param: ValDef)(using Context): Boolean =
2026+
val owner = sym.maybeOwner.maybeOwner
2027+
val accessorSyms = maybeParamAccessors(owner, sym)
2028+
owner.infoOrCompleter match
2029+
// case info: ClassInfo =>
2030+
// info.parents.foreach(println)
2031+
// info.parents.exists(tpeContainsSymbolRef(_, accessorSyms))
2032+
case _ => false
2033+
2034+
private def namedTypeWithPrefixContainsSymbolRef(tpe: Type, syms: List[Symbol])(using Context): Boolean = tpe match
2035+
case tpe: NamedType => tpe.prefix.exists && tpeContainsSymbolRef(tpe.prefix, syms)
2036+
case _ => false
2037+
2038+
private def tpeContainsSymbolRef(tpe: Type, syms: List[Symbol])(using Context): Boolean =
2039+
tpe.termSymbol.exists && syms.contains(tpe.termSymbol)
2040+
|| tpe.argInfos.exists(tpeContainsSymbolRef(_, syms))
2041+
|| namedTypeWithPrefixContainsSymbolRef(tpe, syms)
2042+
2043+
private def maybeParamAccessors(owner: Symbol, sym: Symbol)(using Context): List[Symbol] =
2044+
owner.infoOrCompleter match
2045+
case info: ClassInfo =>
2046+
info.decls.lookupAll(sym.name).filter(d => d.is(ParamAccessor)).toList
2047+
case _ => List.empty
2048+
19972049
/** Under x.modularity, set every context bound evidence parameter of a class to be tracked,
19982050
* provided it has a type that has an abstract type member. Reset private and local flags
19992051
* so that the parameter becomes a `val`.

tests/pos/infer-tracked.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import scala.language.experimental.modularity
2+
import scala.language.future
3+
4+
abstract class C:
5+
type T
6+
def foo: T
7+
8+
class F(val x: C):
9+
val result: x.T = x.foo
10+
11+
class G(override val x: C) extends F(x)
12+
13+
def Test =
14+
val c = new C:
15+
type T = Int
16+
def foo = 42
17+
18+
val f = new F(c)
19+
val i: Int = f.result
20+
21+
// val g = new G(c)
22+
// val j: Int = g.result

0 commit comments

Comments
 (0)