@@ -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 =
@@ -993,15 +1002,19 @@ class Namer { typer: Typer =>
9931002
9941003 /** If completion of the owner of the to be completed symbol has not yet started,
9951004 * 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
9971006 * yet completed. Test case is pos/i10967.scala.
9981007 */
9991008 override def needsCompletion (symd : SymDenotation )(using Context ): Boolean =
10001009 val owner = symd.owner
10011010 ! owner.exists
10021011 || owner.is(Touched )
10031012 || {
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()
10051018 ! symd.isCompleted
10061019 }
10071020
@@ -1526,12 +1539,9 @@ class Namer { typer: Typer =>
15261539 index(constr)
15271540 index(rest)(using localCtx)
15281541
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)
15351545 case _ =>
15361546
15371547 tempInfo = denot.asClass.classInfo.integrateOpaqueMembers.asInstanceOf [TempClassInfo ]
@@ -1762,6 +1772,17 @@ class Namer { typer: Typer =>
17621772 val sym = tree.symbol
17631773 if sym.isConstructor then sym.owner else sym
17641774
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+
17651786 /** The signature of a module valdef.
17661787 * This will compute the corresponding module class TypeRef immediately
17671788 * without going through the defined type of the ValDef. This is necessary
@@ -1860,31 +1881,6 @@ class Namer { typer: Typer =>
18601881 // Beware: ddef.name need not match sym.name if sym was freshened!
18611882 val isConstructor = sym.name == nme.CONSTRUCTOR
18621883
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-
18881884 // The following 3 lines replace what was previously just completeParams(tparams).
18891885 // But that can cause bad bounds being computed, as witnessed by
18901886 // tests/pos/paramcycle.scala. The problematic sequence is this:
@@ -1908,39 +1904,16 @@ class Namer { typer: Typer =>
19081904 // 3. Info of CP is computed (to be copied to DP).
19091905 // 4. CP is completed.
19101906 // 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 )
19131909 val completedTypeParams =
19141910 for tparam <- ddef.leadingTypeParams yield typedAheadExpr(tparam).symbol
19151911 if completedTypeParams.forall(_.isType) then
19161912 completer.setCompletedTypeParams(completedTypeParams.asInstanceOf [List [TypeSymbol ]])
1917- ddef.trailingParamss.foreach(completeParams )
1913+ completeTrailingParamss(ddef, sym, indexingCtor = false )
19181914 val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
19191915 sym.setParamss(paramSymss)
19201916
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-
19441917 def wrapMethType (restpe : Type ): Type =
19451918 instantiateDependent(restpe, paramSymss)
19461919 methodType(paramSymss, restpe, ddef.mods.is(JavaDefined ))
@@ -1949,11 +1922,11 @@ class Namer { typer: Typer =>
19491922 wrapMethType(addParamRefinements(restpe, paramSymss))
19501923
19511924 if isConstructor then
1952- if sym.isPrimaryConstructor && Feature .enabled(modularity) then
1953- ddef.termParamss.foreach(_.foreach(setTracked))
19541925 // set result type tree to unit, but take the current class as result type of the symbol
19551926 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
19571930 else if sym.isAllOf(Given | Method ) && Feature .enabled(modularity) then
19581931 // set every context bound evidence parameter of a given companion method
19591932 // to be tracked, provided it has a type that has an abstract type member.
@@ -1966,6 +1939,75 @@ class Namer { typer: Typer =>
19661939 valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
19671940 end defDefSig
19681941
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+
19692011 def inferredResultType (
19702012 mdef : ValOrDefDef ,
19712013 sym : Symbol ,
0 commit comments