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