@@ -822,8 +822,11 @@ class Namer { typer: Typer =>
822
822
if (sym.is(Module )) moduleValSig(sym)
823
823
else valOrDefDefSig(original, sym, Nil , identity)(using localContext(sym).setNewScope)
824
824
case original : DefDef =>
825
- val typer1 = ctx.typer.newLikeThis(ctx.nestingLevel + 1 )
826
- nestedTyper(sym) = typer1
825
+ // For the primary constructor DefDef, it is:
826
+ // * indexed as a part of completing the class, with indexConstructor; and
827
+ // * typed ahead when completing the constructor
828
+ // So we need to make sure to reuse the same local/nested typer.
829
+ val typer1 = nestedTyper.getOrElseUpdate(sym, ctx.typer.newLikeThis(ctx.nestingLevel + 1 ))
827
830
typer1.defDefSig(original, sym, this )(using localContext(sym).setTyper(typer1))
828
831
case imp : Import =>
829
832
try
@@ -833,6 +836,12 @@ class Namer { typer: Typer =>
833
836
typr.println(s " error while completing ${imp.expr}" )
834
837
throw ex
835
838
839
+ /** Context setup for indexing the constructor. */
840
+ def indexConstructor (constr : DefDef , sym : Symbol ): Unit =
841
+ val typer1 = ctx.typer.newLikeThis(ctx.nestingLevel + 1 )
842
+ nestedTyper(sym) = typer1
843
+ typer1.indexConstructor(constr, sym)(using localContext(sym).setTyper(typer1))
844
+
836
845
final override def complete (denot : SymDenotation )(using Context ): Unit = {
837
846
if (Config .showCompletions && ctx.typerState != creationContext.typerState) {
838
847
def levels (c : Context ): Int =
@@ -993,15 +1002,19 @@ class Namer { typer: Typer =>
993
1002
994
1003
/** If completion of the owner of the to be completed symbol has not yet started,
995
1004
* complete the owner first and check again. This prevents cyclic references
996
- * where we need to copmplete a type parameter that has an owner that is not
1005
+ * where we need to complete a type parameter that has an owner that is not
997
1006
* yet completed. Test case is pos/i10967.scala.
998
1007
*/
999
1008
override def needsCompletion (symd : SymDenotation )(using Context ): Boolean =
1000
1009
val owner = symd.owner
1001
1010
! owner.exists
1002
1011
|| owner.is(Touched )
1003
1012
|| {
1004
- owner.ensureCompleted()
1013
+ // Only complete the owner if it's a type (eg. the class that owns a type parameter)
1014
+ // This avoids completing primary constructor methods while completing the type of one of its type parameters
1015
+ // See i15177.scala.
1016
+ if owner.isType then
1017
+ owner.ensureCompleted()
1005
1018
! symd.isCompleted
1006
1019
}
1007
1020
@@ -1526,12 +1539,9 @@ class Namer { typer: Typer =>
1526
1539
index(constr)
1527
1540
index(rest)(using localCtx)
1528
1541
1529
- symbolOfTree(constr).info.stripPoly match // Completes constr symbol as a side effect
1530
- case mt : MethodType if cls.is(Case ) && mt.isParamDependent =>
1531
- // See issue #8073 for background
1532
- report.error(
1533
- em """ Implementation restriction: case classes cannot have dependencies between parameters """ ,
1534
- cls.srcPos)
1542
+ val constrSym = symbolOfTree(constr)
1543
+ constrSym.infoOrCompleter match
1544
+ case completer : Completer => completer.indexConstructor(constr, constrSym)
1535
1545
case _ =>
1536
1546
1537
1547
tempInfo = denot.asClass.classInfo.integrateOpaqueMembers.asInstanceOf [TempClassInfo ]
@@ -1762,6 +1772,17 @@ class Namer { typer: Typer =>
1762
1772
val sym = tree.symbol
1763
1773
if sym.isConstructor then sym.owner else sym
1764
1774
1775
+ /** Index the primary constructor of a class, as a part of completing that class.
1776
+ * This allows the rest of the constructor completion to be deferred,
1777
+ * which avoids non-cyclic classes failing, e.g. pos/i15177.
1778
+ */
1779
+ def indexConstructor (constr : DefDef , sym : Symbol )(using Context ): Unit =
1780
+ index(constr.leadingTypeParams)
1781
+ sym.owner.typeParams.foreach(_.ensureCompleted())
1782
+ completeTrailingParamss(constr, sym, indexingCtor = true )
1783
+ if Feature .enabled(modularity) then
1784
+ constr.termParamss.foreach(_.foreach(setTracked))
1785
+
1765
1786
/** The signature of a module valdef.
1766
1787
* This will compute the corresponding module class TypeRef immediately
1767
1788
* without going through the defined type of the ValDef. This is necessary
@@ -1860,31 +1881,6 @@ class Namer { typer: Typer =>
1860
1881
// Beware: ddef.name need not match sym.name if sym was freshened!
1861
1882
val isConstructor = sym.name == nme.CONSTRUCTOR
1862
1883
1863
- // A map from context-bounded type parameters to associated evidence parameter names
1864
- val witnessNamesOfParam = mutable.Map [TypeDef , List [TermName ]]()
1865
- if ! ddef.name.is(DefaultGetterName ) && ! sym.is(Synthetic ) then
1866
- for params <- ddef.paramss; case tdef : TypeDef <- params do
1867
- for case WitnessNamesAnnot (ws) <- tdef.mods.annotations do
1868
- witnessNamesOfParam(tdef) = ws
1869
-
1870
- /** Is each name in `wnames` defined somewhere in the longest prefix of all `params`
1871
- * that have been typed ahead (i.e. that carry the TypedAhead attachment)?
1872
- */
1873
- def allParamsSeen (wnames : List [TermName ], params : List [MemberDef ]) =
1874
- (wnames.toSet[Name ] -- params.takeWhile(_.hasAttachment(TypedAhead )).map(_.name)).isEmpty
1875
-
1876
- /** Enter and typecheck parameter list.
1877
- * Once all witness parameters for a context bound are seen, create a
1878
- * context bound companion for it.
1879
- */
1880
- def completeParams (params : List [MemberDef ])(using Context ): Unit =
1881
- index(params)
1882
- for param <- params do
1883
- typedAheadExpr(param)
1884
- for (tdef, wnames) <- witnessNamesOfParam do
1885
- if wnames.contains(param.name) && allParamsSeen(wnames, params) then
1886
- addContextBoundCompanionFor(symbolOfTree(tdef), wnames, params.map(symbolOfTree))
1887
-
1888
1884
// The following 3 lines replace what was previously just completeParams(tparams).
1889
1885
// But that can cause bad bounds being computed, as witnessed by
1890
1886
// tests/pos/paramcycle.scala. The problematic sequence is this:
@@ -1908,39 +1904,16 @@ class Namer { typer: Typer =>
1908
1904
// 3. Info of CP is computed (to be copied to DP).
1909
1905
// 4. CP is completed.
1910
1906
// 5. Info of CP is copied to DP and DP is completed.
1911
- index(ddef.leadingTypeParams)
1912
- if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted() )
1907
+ if ! sym.isPrimaryConstructor then
1908
+ index(ddef.leadingTypeParams )
1913
1909
val completedTypeParams =
1914
1910
for tparam <- ddef.leadingTypeParams yield typedAheadExpr(tparam).symbol
1915
1911
if completedTypeParams.forall(_.isType) then
1916
1912
completer.setCompletedTypeParams(completedTypeParams.asInstanceOf [List [TypeSymbol ]])
1917
- ddef.trailingParamss.foreach(completeParams )
1913
+ completeTrailingParamss(ddef, sym, indexingCtor = false )
1918
1914
val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
1919
1915
sym.setParamss(paramSymss)
1920
1916
1921
- /** Under x.modularity, we add `tracked` to context bound witnesses
1922
- * that have abstract type members
1923
- */
1924
- def needsTracked (sym : Symbol , param : ValDef )(using Context ) =
1925
- ! sym.is(Tracked )
1926
- && param.hasAttachment(ContextBoundParam )
1927
- && sym.info.memberNames(abstractTypeNameFilter).nonEmpty
1928
-
1929
- /** Under x.modularity, set every context bound evidence parameter of a class to be tracked,
1930
- * provided it has a type that has an abstract type member. Reset private and local flags
1931
- * so that the parameter becomes a `val`.
1932
- */
1933
- def setTracked (param : ValDef ): Unit =
1934
- val sym = symbolOfTree(param)
1935
- sym.maybeOwner.maybeOwner.infoOrCompleter match
1936
- case info : TempClassInfo if needsTracked(sym, param) =>
1937
- typr.println(i " set tracked $param, $sym: ${sym.info} containing ${sym.info.memberNames(abstractTypeNameFilter).toList}" )
1938
- for acc <- info.decls.lookupAll(sym.name) if acc.is(ParamAccessor ) do
1939
- acc.resetFlag(PrivateLocal )
1940
- acc.setFlag(Tracked )
1941
- sym.setFlag(Tracked )
1942
- case _ =>
1943
-
1944
1917
def wrapMethType (restpe : Type ): Type =
1945
1918
instantiateDependent(restpe, paramSymss)
1946
1919
methodType(paramSymss, restpe, ddef.mods.is(JavaDefined ))
@@ -1949,11 +1922,11 @@ class Namer { typer: Typer =>
1949
1922
wrapMethType(addParamRefinements(restpe, paramSymss))
1950
1923
1951
1924
if isConstructor then
1952
- if sym.isPrimaryConstructor && Feature .enabled(modularity) then
1953
- ddef.termParamss.foreach(_.foreach(setTracked))
1954
1925
// set result type tree to unit, but take the current class as result type of the symbol
1955
1926
typedAheadType(ddef.tpt, defn.UnitType )
1956
- wrapMethType(effectiveResultType(sym, paramSymss))
1927
+ val mt = wrapMethType(effectiveResultType(sym, paramSymss))
1928
+ if sym.isPrimaryConstructor then checkCaseClassParamDependencies(mt, sym.owner)
1929
+ mt
1957
1930
else if sym.isAllOf(Given | Method ) && Feature .enabled(modularity) then
1958
1931
// set every context bound evidence parameter of a given companion method
1959
1932
// to be tracked, provided it has a type that has an abstract type member.
@@ -1966,6 +1939,75 @@ class Namer { typer: Typer =>
1966
1939
valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
1967
1940
end defDefSig
1968
1941
1942
+ /** Complete the trailing parameters of a DefDef,
1943
+ * as a part of indexing the primary constructor or
1944
+ * as a part of completing a DefDef, including the primary constructor.
1945
+ */
1946
+ def completeTrailingParamss (ddef : DefDef , sym : Symbol , indexingCtor : Boolean )(using Context ): Unit =
1947
+ // A map from context-bounded type parameters to associated evidence parameter names
1948
+ val witnessNamesOfParam = mutable.Map [TypeDef , List [TermName ]]()
1949
+ if ! ddef.name.is(DefaultGetterName ) && ! sym.is(Synthetic ) && (indexingCtor || ! sym.isPrimaryConstructor) then
1950
+ for params <- ddef.paramss; case tdef : TypeDef <- params do
1951
+ for case WitnessNamesAnnot (ws) <- tdef.mods.annotations do
1952
+ witnessNamesOfParam(tdef) = ws
1953
+
1954
+ /** Is each name in `wnames` defined somewhere in the previous parameters? */
1955
+ def allParamsSeen (wnames : List [TermName ], prevParams : Set [Name ]) =
1956
+ (wnames.toSet[Name ] -- prevParams).isEmpty
1957
+
1958
+ /** Enter and typecheck parameter list.
1959
+ * Once all witness parameters for a context bound are seen, create a
1960
+ * context bound companion for it.
1961
+ */
1962
+ def completeParams (params : List [MemberDef ])(using Context ): Unit =
1963
+ if indexingCtor || ! sym.isPrimaryConstructor then
1964
+ index(params)
1965
+ var prevParams = Set .empty[Name ]
1966
+ for param <- params do
1967
+ if ! indexingCtor then
1968
+ typedAheadExpr(param)
1969
+
1970
+ prevParams += param.name
1971
+ for (tdef, wnames) <- witnessNamesOfParam do
1972
+ if wnames.contains(param.name) && allParamsSeen(wnames, prevParams) then
1973
+ addContextBoundCompanionFor(symbolOfTree(tdef), wnames, params.map(symbolOfTree))
1974
+
1975
+ ddef.trailingParamss.foreach(completeParams)
1976
+ end completeTrailingParamss
1977
+
1978
+ /** Checks an implementation restriction on case classes. */
1979
+ def checkCaseClassParamDependencies (mt : Type , cls : Symbol )(using Context ): Unit =
1980
+ mt.stripPoly match
1981
+ case mt : MethodType if cls.is(Case ) && mt.isParamDependent =>
1982
+ // See issue #8073 for background
1983
+ report.error(
1984
+ em """ Implementation restriction: case classes cannot have dependencies between parameters """ ,
1985
+ cls.srcPos)
1986
+ case _ =>
1987
+
1988
+ /** Under x.modularity, we add `tracked` to context bound witnesses
1989
+ * that have abstract type members
1990
+ */
1991
+ def needsTracked (sym : Symbol , param : ValDef )(using Context ) =
1992
+ ! sym.is(Tracked )
1993
+ && param.hasAttachment(ContextBoundParam )
1994
+ && sym.info.memberNames(abstractTypeNameFilter).nonEmpty
1995
+
1996
+ /** Under x.modularity, set every context bound evidence parameter of a class to be tracked,
1997
+ * provided it has a type that has an abstract type member. Reset private and local flags
1998
+ * so that the parameter becomes a `val`.
1999
+ */
2000
+ def setTracked (param : ValDef )(using Context ): Unit =
2001
+ val sym = symbolOfTree(param)
2002
+ sym.maybeOwner.maybeOwner.infoOrCompleter match
2003
+ case info : ClassInfo if needsTracked(sym, param) =>
2004
+ typr.println(i " set tracked $param, $sym: ${sym.info} containing ${sym.info.memberNames(abstractTypeNameFilter).toList}" )
2005
+ for acc <- info.decls.lookupAll(sym.name) if acc.is(ParamAccessor ) do
2006
+ acc.resetFlag(PrivateLocal )
2007
+ acc.setFlag(Tracked )
2008
+ sym.setFlag(Tracked )
2009
+ case _ =>
2010
+
1969
2011
def inferredResultType (
1970
2012
mdef : ValOrDefDef ,
1971
2013
sym : Symbol ,
0 commit comments