@@ -822,8 +822,11 @@ class Namer { typer: Typer =>
822822 if (sym.is(Module )) moduleValSig(sym)
823823 else valOrDefDefSig(original, sym, Nil , identity)(using localContext(sym).setNewScope)
824824 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 ))
827830 typer1.defDefSig(original, sym, this )(using localContext(sym).setTyper(typer1))
828831 case imp : Import =>
829832 try
@@ -833,6 +836,12 @@ class Namer { typer: Typer =>
833836 typr.println(s " error while completing ${imp.expr}" )
834837 throw ex
835838
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+
836845 final override def complete (denot : SymDenotation )(using Context ): Unit = {
837846 if (Config .showCompletions && ctx.typerState != creationContext.typerState) {
838847 def levels (c : Context ): Int =
@@ -988,15 +997,19 @@ class Namer { typer: Typer =>
988997
989998 /** If completion of the owner of the to be completed symbol has not yet started,
990999 * 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
9921001 * yet completed. Test case is pos/i10967.scala.
9931002 */
9941003 override def needsCompletion (symd : SymDenotation )(using Context ): Boolean =
9951004 val owner = symd.owner
9961005 ! owner.exists
9971006 || owner.is(Touched )
9981007 || {
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()
10001013 ! symd.isCompleted
10011014 }
10021015
@@ -1521,7 +1534,10 @@ class Namer { typer: Typer =>
15211534 index(constr)
15221535 index(rest)(using localCtx)
15231536
1524- checkCaseClassParamDependencies(symbolOfTree(constr).info, cls) // Completes constr symbol as a side effect
1537+ val constrSym = symbolOfTree(constr)
1538+ constrSym.infoOrCompleter match
1539+ case completer : Completer => completer.indexConstructor(constr, constrSym)
1540+ case _ =>
15251541
15261542 tempInfo = denot.asClass.classInfo.integrateOpaqueMembers.asInstanceOf [TempClassInfo ]
15271543 denot.info = savedInfo
@@ -1751,6 +1767,17 @@ class Namer { typer: Typer =>
17511767 val sym = tree.symbol
17521768 if sym.isConstructor then sym.owner else sym
17531769
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+
17541781 /** The signature of a module valdef.
17551782 * This will compute the corresponding module class TypeRef immediately
17561783 * without going through the defined type of the ValDef. This is necessary
@@ -1872,13 +1899,13 @@ class Namer { typer: Typer =>
18721899 // 3. Info of CP is computed (to be copied to DP).
18731900 // 4. CP is completed.
18741901 // 5. Info of CP is copied to DP and DP is completed.
1875- index(ddef.leadingTypeParams)
1876- if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted() )
1902+ if ! sym.isPrimaryConstructor then
1903+ index(ddef.leadingTypeParams )
18771904 val completedTypeParams =
18781905 for tparam <- ddef.leadingTypeParams yield typedAheadExpr(tparam).symbol
18791906 if completedTypeParams.forall(_.isType) then
18801907 completer.setCompletedTypeParams(completedTypeParams.asInstanceOf [List [TypeSymbol ]])
1881- completeTrailingParamss(ddef, sym)
1908+ completeTrailingParamss(ddef, sym, indexingCtor = false )
18821909 val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
18831910 sym.setParamss(paramSymss)
18841911
@@ -1890,11 +1917,11 @@ class Namer { typer: Typer =>
18901917 wrapMethType(addParamRefinements(restpe, paramSymss))
18911918
18921919 if isConstructor then
1893- if sym.isPrimaryConstructor && Feature .enabled(modularity) then
1894- ddef.termParamss.foreach(_.foreach(setTracked))
18951920 // set result type tree to unit, but take the current class as result type of the symbol
18961921 typedAheadType(ddef.tpt, defn.UnitType )
1897- wrapMethType(effectiveResultType(sym, paramSymss))
1922+ val mt = wrapMethType(effectiveResultType(sym, paramSymss))
1923+ if sym.isPrimaryConstructor then checkCaseClassParamDependencies(mt, sym.owner)
1924+ mt
18981925 else if sym.isAllOf(Given | Method ) && Feature .enabled(modularity) then
18991926 // set every context bound evidence parameter of a given companion method
19001927 // to be tracked, provided it has a type that has an abstract type member.
@@ -1907,30 +1934,37 @@ class Namer { typer: Typer =>
19071934 valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
19081935 end defDefSig
19091936
1910- def completeTrailingParamss (ddef : DefDef , sym : Symbol )(using Context ): Unit =
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 =
19111942 // A map from context-bounded type parameters to associated evidence parameter names
19121943 val witnessNamesOfParam = mutable.Map [TypeDef , List [TermName ]]()
1913- if ! ddef.name.is(DefaultGetterName ) && ! sym.is(Synthetic ) then
1944+ if ! ddef.name.is(DefaultGetterName ) && ! sym.is(Synthetic ) && (indexingCtor || ! sym.isPrimaryConstructor) then
19141945 for params <- ddef.paramss; case tdef : TypeDef <- params do
19151946 for case WitnessNamesAnnot (ws) <- tdef.mods.annotations do
19161947 witnessNamesOfParam(tdef) = ws
19171948
1918- /** Is each name in `wnames` defined somewhere in the longest prefix of all `params`
1919- * that have been typed ahead (i.e. that carry the TypedAhead attachment)?
1920- */
1921- def allParamsSeen (wnames : List [TermName ], params : List [MemberDef ]) =
1922- (wnames.toSet[Name ] -- params.takeWhile(_.hasAttachment(TypedAhead )).map(_.name)).isEmpty
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
19231952
19241953 /** Enter and typecheck parameter list.
19251954 * Once all witness parameters for a context bound are seen, create a
19261955 * context bound companion for it.
19271956 */
19281957 def completeParams (params : List [MemberDef ])(using Context ): Unit =
1929- index(params)
1958+ if indexingCtor || ! sym.isPrimaryConstructor then
1959+ index(params)
1960+ var prevParams = Set .empty[Name ]
19301961 for param <- params do
1931- typedAheadExpr(param)
1962+ if ! indexingCtor then
1963+ typedAheadExpr(param)
1964+
1965+ prevParams += param.name
19321966 for (tdef, wnames) <- witnessNamesOfParam do
1933- if wnames.contains(param.name) && allParamsSeen(wnames, params ) then
1967+ if wnames.contains(param.name) && allParamsSeen(wnames, prevParams ) then
19341968 addContextBoundCompanionFor(symbolOfTree(tdef), wnames, params.map(symbolOfTree))
19351969
19361970 ddef.trailingParamss.foreach(completeParams)
@@ -1961,7 +1995,7 @@ class Namer { typer: Typer =>
19611995 def setTracked (param : ValDef )(using Context ): Unit =
19621996 val sym = symbolOfTree(param)
19631997 sym.maybeOwner.maybeOwner.infoOrCompleter match
1964- case info : TempClassInfo if needsTracked(sym, param) =>
1998+ case info : ClassInfo if needsTracked(sym, param) =>
19651999 typr.println(i " set tracked $param, $sym: ${sym.info} containing ${sym.info.memberNames(abstractTypeNameFilter).toList}" )
19662000 for acc <- info.decls.lookupAll(sym.name) if acc.is(ParamAccessor ) do
19672001 acc.resetFlag(PrivateLocal )
0 commit comments