@@ -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 =
@@ -986,15 +995,18 @@ class Namer { typer: Typer =>
986995
987996 /** If completion of the owner of the to be completed symbol has not yet started,
988997 * complete the owner first and check again. This prevents cyclic references
989- * where we need to copmplete a type parameter that has an owner that is not
998+ * where we need to complete a type parameter that has an owner that is not
990999 * yet completed. Test case is pos/i10967.scala.
9911000 */
9921001 override def needsCompletion (symd : SymDenotation )(using Context ): Boolean =
9931002 val owner = symd.owner
9941003 ! owner.exists
9951004 || owner.is(Touched )
9961005 || {
997- owner.ensureCompleted()
1006+ // Only complete the owner if it's a type (eg. the class that owns a type parameter)
1007+ // This avoids completing primary constructor methods while completing the type of one of its type parameters
1008+ if owner.isType then
1009+ owner.ensureCompleted()
9981010 ! symd.isCompleted
9991011 }
10001012
@@ -1519,12 +1531,9 @@ class Namer { typer: Typer =>
15191531 index(constr)
15201532 index(rest)(using localCtx)
15211533
1522- symbolOfTree(constr).info.stripPoly match // Completes constr symbol as a side effect
1523- case mt : MethodType if cls.is(Case ) && mt.isParamDependent =>
1524- // See issue #8073 for background
1525- report.error(
1526- em """ Implementation restriction: case classes cannot have dependencies between parameters """ ,
1527- cls.srcPos)
1534+ val constrSym = symbolOfTree(constr)
1535+ constrSym.infoOrCompleter match
1536+ case completer : Completer => completer.indexConstructor(constr, constrSym)
15281537 case _ =>
15291538
15301539 tempInfo = denot.asClass.classInfo.integrateOpaqueMembers.asInstanceOf [TempClassInfo ]
@@ -1853,31 +1862,6 @@ class Namer { typer: Typer =>
18531862 // Beware: ddef.name need not match sym.name if sym was freshened!
18541863 val isConstructor = sym.name == nme.CONSTRUCTOR
18551864
1856- // A map from context-bounded type parameters to associated evidence parameter names
1857- val witnessNamesOfParam = mutable.Map [TypeDef , List [TermName ]]()
1858- if ! ddef.name.is(DefaultGetterName ) && ! sym.is(Synthetic ) then
1859- for params <- ddef.paramss; case tdef : TypeDef <- params do
1860- for case WitnessNamesAnnot (ws) <- tdef.mods.annotations do
1861- witnessNamesOfParam(tdef) = ws
1862-
1863- /** Is each name in `wnames` defined somewhere in the longest prefix of all `params`
1864- * that have been typed ahead (i.e. that carry the TypedAhead attachment)?
1865- */
1866- def allParamsSeen (wnames : List [TermName ], params : List [MemberDef ]) =
1867- (wnames.toSet[Name ] -- params.takeWhile(_.hasAttachment(TypedAhead )).map(_.name)).isEmpty
1868-
1869- /** Enter and typecheck parameter list.
1870- * Once all witness parameters for a context bound are seen, create a
1871- * context bound companion for it.
1872- */
1873- def completeParams (params : List [MemberDef ])(using Context ): Unit =
1874- index(params)
1875- for param <- params do
1876- typedAheadExpr(param)
1877- for (tdef, wnames) <- witnessNamesOfParam do
1878- if wnames.contains(param.name) && allParamsSeen(wnames, params) then
1879- addContextBoundCompanionFor(symbolOfTree(tdef), wnames, params.map(symbolOfTree))
1880-
18811865 // The following 3 lines replace what was previously just completeParams(tparams).
18821866 // But that can cause bad bounds being computed, as witnessed by
18831867 // tests/pos/paramcycle.scala. The problematic sequence is this:
@@ -1901,39 +1885,15 @@ class Namer { typer: Typer =>
19011885 // 3. Info of CP is computed (to be copied to DP).
19021886 // 4. CP is completed.
19031887 // 5. Info of CP is copied to DP and DP is completed.
1904- index(ddef.leadingTypeParams)
1905- if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted())
1888+ if ! sym.isPrimaryConstructor then index(ddef.leadingTypeParams)
19061889 val completedTypeParams =
19071890 for tparam <- ddef.leadingTypeParams yield typedAheadExpr(tparam).symbol
19081891 if completedTypeParams.forall(_.isType) then
19091892 completer.setCompletedTypeParams(completedTypeParams.asInstanceOf [List [TypeSymbol ]])
1910- ddef.trailingParamss.foreach(completeParams )
1893+ completeTrailingParamss(ddef, sym )
19111894 val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
19121895 sym.setParamss(paramSymss)
19131896
1914- /** Under x.modularity, we add `tracked` to context bound witnesses
1915- * that have abstract type members
1916- */
1917- def needsTracked (sym : Symbol , param : ValDef )(using Context ) =
1918- ! sym.is(Tracked )
1919- && param.hasAttachment(ContextBoundParam )
1920- && sym.info.memberNames(abstractTypeNameFilter).nonEmpty
1921-
1922- /** Under x.modularity, set every context bound evidence parameter of a class to be tracked,
1923- * provided it has a type that has an abstract type member. Reset private and local flags
1924- * so that the parameter becomes a `val`.
1925- */
1926- def setTracked (param : ValDef ): Unit =
1927- val sym = symbolOfTree(param)
1928- sym.maybeOwner.maybeOwner.infoOrCompleter match
1929- case info : TempClassInfo if needsTracked(sym, param) =>
1930- typr.println(i " set tracked $param, $sym: ${sym.info} containing ${sym.info.memberNames(abstractTypeNameFilter).toList}" )
1931- for acc <- info.decls.lookupAll(sym.name) if acc.is(ParamAccessor ) do
1932- acc.resetFlag(PrivateLocal )
1933- acc.setFlag(Tracked )
1934- sym.setFlag(Tracked )
1935- case _ =>
1936-
19371897 def wrapMethType (restpe : Type ): Type =
19381898 instantiateDependent(restpe, paramSymss)
19391899 methodType(paramSymss, restpe, ddef.mods.is(JavaDefined ))
@@ -1942,11 +1902,18 @@ class Namer { typer: Typer =>
19421902 wrapMethType(addParamRefinements(restpe, paramSymss))
19431903
19441904 if isConstructor then
1945- if sym.isPrimaryConstructor && Feature .enabled(modularity) then
1946- ddef.termParamss.foreach(_.foreach(setTracked))
19471905 // set result type tree to unit, but take the current class as result type of the symbol
19481906 typedAheadType(ddef.tpt, defn.UnitType )
1949- wrapMethType(effectiveResultType(sym, paramSymss))
1907+ val mt = wrapMethType(effectiveResultType(sym, paramSymss))
1908+ if sym.isPrimaryConstructor then
1909+ mt.stripPoly match
1910+ case mt : MethodType if sym.owner.is(Case ) && mt.isParamDependent =>
1911+ // See issue #8073 for background
1912+ report.error(
1913+ em """ Implementation restriction: case classes cannot have dependencies between parameters """ ,
1914+ sym.owner.srcPos)
1915+ case _ =>
1916+ mt
19501917 else if sym.isAllOf(Given | Method ) && Feature .enabled(modularity) then
19511918 // set every context bound evidence parameter of a given companion method
19521919 // to be tracked, provided it has a type that has an abstract type member.
@@ -1959,6 +1926,82 @@ class Namer { typer: Typer =>
19591926 valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
19601927 end defDefSig
19611928
1929+ /** Index the primary constructor of a class, as a part of completing that class.
1930+ * This allows the rest of the constructor completion to be deferred,
1931+ * which avoids non-cyclic classes failing, e.g. pos/i15177.
1932+ */
1933+ def indexConstructor (constr : DefDef , sym : Symbol )(using Context ): Unit =
1934+ index(constr.leadingTypeParams)
1935+ sym.owner.typeParams.foreach(_.ensureCompleted())
1936+ completeTrailingParamss(constr, sym, indexingCtor = true )
1937+ if Feature .enabled(modularity) then
1938+ constr.termParamss.foreach(_.foreach(setTracked))
1939+
1940+ /** Complete the trailing parameters of a DefDef,
1941+ * as a part of indexing the primary constructor or
1942+ * as a part of completing a DefDef, including the primary constructor.
1943+ */
1944+ def completeTrailingParamss (ddef : DefDef , sym : Symbol , indexingCtor : Boolean = false )(using Context ): Unit =
1945+ // A map from context-bounded type parameters to associated evidence parameter names
1946+ val witnessNamesOfParam = mutable.Map [TypeDef , List [TermName ]]()
1947+ if ! ddef.name.is(DefaultGetterName ) && ! sym.is(Synthetic ) && (indexingCtor || ! sym.isPrimaryConstructor) then
1948+ for params <- ddef.paramss; case tdef : TypeDef <- params do
1949+ for case WitnessNamesAnnot (ws) <- tdef.mods.annotations do
1950+ witnessNamesOfParam(tdef) = ws
1951+
1952+ /** Is each name in `wnames` defined somewhere in the previous parameters? */
1953+ def allParamsSeen (wnames : List [TermName ], prevParams1 : List [Name ]) =
1954+ (wnames.toSet[Name ] -- prevParams1).isEmpty
1955+
1956+ /** Enter and typecheck parameter list.
1957+ * Once all witness parameters for a context bound are seen, create a
1958+ * context bound companion for it.
1959+ */
1960+ def completeParams (params : List [MemberDef ])(using Context ): Unit =
1961+ if indexingCtor || ! sym.isPrimaryConstructor then index(params)
1962+ val paramSyms = params.map(symbolOfTree)
1963+
1964+ def loop (nextParams : List [MemberDef ], prevParams : List [Name ]): Unit = nextParams match
1965+ case param :: nextParams1 =>
1966+ if ! indexingCtor then
1967+ typedAheadExpr(param)
1968+
1969+ val prevParams1 = param.name :: prevParams
1970+ for (tdef, wnames) <- witnessNamesOfParam do
1971+ if wnames.contains(param.name) && allParamsSeen(wnames, prevParams1) then
1972+ addContextBoundCompanionFor(symbolOfTree(tdef), wnames, paramSyms)
1973+
1974+ loop(nextParams1, prevParams1)
1975+ case _ =>
1976+ loop(params, Nil )
1977+ end completeParams
1978+
1979+ ddef.trailingParamss.foreach(completeParams)
1980+ end completeTrailingParamss
1981+
1982+ /** Under x.modularity, we add `tracked` to context bound witnesses
1983+ * that have abstract type members
1984+ */
1985+ def needsTracked (sym : Symbol , param : ValDef )(using Context ) =
1986+ ! sym.is(Tracked )
1987+ && param.hasAttachment(ContextBoundParam )
1988+ && sym.info.memberNames(abstractTypeNameFilter).nonEmpty
1989+
1990+ /** Under x.modularity, set every context bound evidence parameter of a class to be tracked,
1991+ * provided it has a type that has an abstract type member. Reset private and local flags
1992+ * so that the parameter becomes a `val`.
1993+ */
1994+ def setTracked (param : ValDef )(using Context ): Unit =
1995+ val sym = symbolOfTree(param)
1996+ sym.maybeOwner.maybeOwner.infoOrCompleter match
1997+ case info : ClassInfo if needsTracked(sym, param) =>
1998+ typr.println(i " set tracked $param, $sym: ${sym.info} containing ${sym.info.memberNames(abstractTypeNameFilter).toList}" )
1999+ for acc <- info.decls.lookupAll(sym.name) if acc.is(ParamAccessor ) do
2000+ acc.resetFlag(PrivateLocal )
2001+ acc.setFlag(Tracked )
2002+ sym.setFlag(Tracked )
2003+ case _ =>
2004+
19622005 def inferredResultType (
19632006 mdef : ValOrDefDef ,
19642007 sym : Symbol ,
0 commit comments