Skip to content

Commit

Permalink
Merge pull request #9712 from som-snytt/issue/5606
Browse files Browse the repository at this point in the history
  • Loading branch information
SethTisue committed Oct 7, 2021
2 parents 147155a + c178b41 commit 933b3c6
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 45 deletions.
29 changes: 22 additions & 7 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Expand Up @@ -274,6 +274,14 @@ self =>
final val InBlock: Location = 1
final val InTemplate: Location = 2

type ParamOwner = Int
object ParamOwner {
final val Class = 0
final val Type = 1
final val TypeParam = 2 // unused
final val Def = 3
}

// These symbols may not yet be loaded (e.g. in the ide) so don't go
// through definitions to obtain the names.
lazy val ScalaValueClassNames = Seq(tpnme.AnyVal,
Expand Down Expand Up @@ -2554,8 +2562,9 @@ self =>
* TypeParam ::= Id TypeParamClauseOpt TypeBounds {`<%` Type} {`:` Type}
* }}}
*/
def typeParamClauseOpt(owner: Name, contextBoundBuf: ListBuffer[Tree]): List[TypeDef] = {
def typeParamClauseOpt(owner: Name, contextBoundBuf: ListBuffer[Tree], ownerKind: ParamOwner): List[TypeDef] = {
def typeParam(ms: Modifiers): TypeDef = {
val isAbstractOwner = ownerKind == ParamOwner.Type //|| ownerKind == ParamOwner.TypeParam
var mods = ms | Flags.PARAM
val start = in.offset
if (owner.isTypeName && isIdent) {
Expand All @@ -2570,10 +2579,16 @@ self =>
val nameOffset = in.offset
checkQMarkDefinition()
checkKeywordDefinition()
// TODO AM: freshTermName(o2p(in.skipToken()), "_$$"), will need to update test suite
val pname: TypeName = wildcardOrIdent().toTypeName
val pname: TypeName =
if (in.token == USCORE && (isAbstractOwner || !currentRun.isScala3)) {
if (!isAbstractOwner)
deprecationWarning(in.offset, "Top-level wildcard is not allowed and will error under -Xsource:3", "2.13.7")
in.nextToken()
freshTypeName("_$$")
}
else ident(skipIt = false).toTypeName
val param = atPos(start, nameOffset) {
val tparams = typeParamClauseOpt(pname, null) // @M TODO null --> no higher-order context bounds for now
val tparams = typeParamClauseOpt(pname, null, ParamOwner.Type) // @M TODO null --> no higher-order context bounds for now
TypeDef(mods, pname, tparams, typeBounds())
}
if (contextBoundBuf ne null) {
Expand Down Expand Up @@ -2903,7 +2918,7 @@ self =>
// [T : B] or [T : => B]; it contains the equivalent implicit parameter type,
// i.e. (B[T] or T => B)
val contextBoundBuf = new ListBuffer[Tree]
val tparams = typeParamClauseOpt(name, contextBoundBuf)
val tparams = typeParamClauseOpt(name, contextBoundBuf, ParamOwner.Def)
val vparamss = paramClauses(name, contextBoundBuf.toList, ofCaseClass = false)
newLineOptWhenFollowedBy(LBRACE)
var restype = fromWithinReturnType(typedOpt())
Expand Down Expand Up @@ -3005,7 +3020,7 @@ self =>
checkKeywordDefinition()
val name = identForType()
// @M! a type alias as well as an abstract type may declare type parameters
val tparams = typeParamClauseOpt(name, null)
val tparams = typeParamClauseOpt(name, null, ParamOwner.Type)
in.token match {
case EQUALS =>
in.nextToken()
Expand Down Expand Up @@ -3070,7 +3085,7 @@ self =>
atPos(start, if (name == tpnme.ERROR) start else nameOffset) {
savingClassContextBounds {
val contextBoundBuf = new ListBuffer[Tree]
val tparams = typeParamClauseOpt(name, contextBoundBuf)
val tparams = typeParamClauseOpt(name, contextBoundBuf, ParamOwner.Class)
classContextBounds = contextBoundBuf.toList
val tstart = (in.offset :: classContextBounds.map(_.pos.start)).min
if (!classContextBounds.isEmpty && mods.isTrait) {
Expand Down
21 changes: 11 additions & 10 deletions src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Expand Up @@ -20,14 +20,13 @@ package tools.nsc
package typechecker

import scala.annotation.{nowarn, tailrec}
import scala.collection.mutable
import mutable.{LinkedHashMap, ListBuffer}
import scala.util.matching.Regex
import symtab.Flags._
import scala.collection.mutable, mutable.{LinkedHashMap, ListBuffer}
import scala.language.implicitConversions
import scala.reflect.internal.util.{ReusableInstance, Statistics, TriState}
import scala.reflect.internal.TypesStats
import scala.language.implicitConversions
import scala.tools.nsc.Reporting.WarningCategory
import scala.util.matching.Regex
import symtab.Flags._

/** This trait provides methods to find various kinds of implicits.
*
Expand Down Expand Up @@ -1830,7 +1829,7 @@ trait Implicits extends splain.SplainData {

private def interpolate(text: String, vars: Map[String, String]) =
Intersobralator.replaceAllIn(text, (_: Regex.Match) match {
case Regex.Groups(v) => Regex quoteReplacement vars.getOrElse(v, "")
case Regex.Groups(v) => Regex.quoteReplacement(vars.getOrElse(v, ""))
// #3915: need to quote replacement string since it may include $'s (such as the interpreter's $iw)
case x => throw new MatchError(x)
})
Expand Down Expand Up @@ -1859,7 +1858,7 @@ trait Implicits extends splain.SplainData {
formatDefSiteMessage(typeArgsAtSym(paramTp).map(_.toString))

def formatDefSiteMessage(typeArgs: List[String]): String =
interpolate(msg, Map(symTypeParamNames zip typeArgs: _*))
interpolate(msg, Map(symTypeParamNames.zip(typeArgs): _*))

def formatParameterMessage(fun: Tree): String = {
val paramNames = referencedTypeParams
Expand All @@ -1880,13 +1879,15 @@ trait Implicits extends splain.SplainData {
case PolyType(tps, tr@TypeRef(_, _, tprefs)) =>
if (tps.corresponds(tprefs)((p, r) => p == r.typeSymbol)) tr.typeConstructor.toString
else {
val freshTpars = tps.mapConserve { case p if p.name == tpnme.WILDCARD => p.cloneSymbol.setName(newTypeName("?T" + tps.indexOf(p))) case p => p }
val freshTpars = tps.mapConserve { p =>
if (p.unexpandedName == tpnme.WILDCARD) p.cloneSymbol.setName(newTypeName("?T" + tps.indexOf(p)))
else p
}
freshTpars.map(_.name).mkString("[", ", ", "] -> ") + tr.instantiateTypeParams(tps, freshTpars.map(_.typeConstructor)).toString
}

case tp => tp.toString
}
interpolate(msg, Map(paramNames zip argTypes: _*))
interpolate(msg, Map(paramNames.zip(argTypes): _*))
}

def validate: Option[String] = {
Expand Down
2 changes: 1 addition & 1 deletion src/partest/scala/tools/partest/ScaladocModelTest.scala
Expand Up @@ -72,7 +72,7 @@ abstract class ScaladocModelTest extends DirectTest {

try {
// 1 - compile with scaladoc and get the model out
val universe = model.getOrElse({sys.error("Scaladoc Model Test ERROR: No universe generated!")})
val universe = model.getOrElse { sys.error("Scaladoc Model Test ERROR: No universe generated!") }
// 2 - check the model generated
testModel(universe.rootPackage)
println("Done.")
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/StdNames.scala
Expand Up @@ -473,6 +473,7 @@ trait StdNames {
def unexpandedName(name: Name): Name =
name.lastIndexOf("$$") match {
case 0 | -1 => name
case 1 if name.charAt(0) == '_' => if (name.isTermName) nme.WILDCARD else tpnme.WILDCARD
case idx0 =>
// Sketchville - We've found $$ but if it's part of $$$ or $$$$
// or something we need to keep the bonus dollars, so e.g. foo$$$outer
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/TypeDebugging.scala
Expand Up @@ -140,7 +140,7 @@ trait TypeDebugging {
def debugString(tp: Type) = debug(tp)
}
def paramString(tp: Type) = typeDebug.str params tp.params
def typeParamsString(tp: Type) = typeDebug.str brackets (tp.typeParams map (_.defString))
def typeParamsString(tp: Type) = typeDebug.str.brackets(tp.typeParams.map(_.defString))
def debugString(tp: Type) = typeDebug debugString tp
}

Expand Down
6 changes: 2 additions & 4 deletions src/reflect/scala/reflect/internal/Types.scala
Expand Up @@ -1559,18 +1559,16 @@ trait Types
/** Bounds notation used in Scala syntax.
* For example +This <: scala.collection.generic.Sorted[K,This].
*/
private[internal] def scalaNotation(typeString: Type => String): String = {
private[internal] def scalaNotation(typeString: Type => String): String =
(if (emptyLowerBound) "" else " >: " + typeString(lo)) +
(if (emptyUpperBound) "" else " <: " + typeString(hi))
}
/** Bounds notation used in https://adriaanm.github.com/files/higher.pdf.
* For example *(scala.collection.generic.Sorted[K,This]).
*/
private[internal] def starNotation(typeString: Type => String): String = {
private[internal] def starNotation(typeString: Type => String): String =
if (emptyLowerBound && emptyUpperBound) ""
else if (emptyLowerBound) s"(${typeString(hi)})"
else s"(${typeString(lo)}, ${typeString(hi)})"
}
override def kind = "TypeBoundsType"
override def mapOver(map: TypeMap): Type = {
val lo1 = map match {
Expand Down
Expand Up @@ -45,7 +45,7 @@ trait ModelFactoryTypeSupport {
appendType0(tp)
case tp :: tps =>
appendType0(tp)
nameBuffer append sep
nameBuffer.append(sep)
appendTypes0(tps, sep)
}

Expand Down Expand Up @@ -202,15 +202,16 @@ trait ModelFactoryTypeSupport {
/* Polymorphic types */
case PolyType(tparams, result) =>
assert(tparams.nonEmpty, "polymorphic type must have at least one type parameter")
def typeParamsToString(tps: List[Symbol]): String = if (tps.isEmpty) "" else
tps.map{tparam =>
tparam.varianceString + tparam.name + typeParamsToString(tparam.typeParams)
}.mkString("[", ", ", "]")
nameBuffer append typeParamsToString(tparams)
def typeParamsToString(tps: List[Symbol]): String =
if (tps.isEmpty) ""
else
tps.map { tparam =>
tparam.varianceString + tparam.unexpandedName + typeParamsToString(tparam.typeParams)
}.mkString("[", ", ", "]")
nameBuffer.append(typeParamsToString(tparams))
appendType0(result)

case et@ExistentialType(quantified, underlying) =>

def appendInfoStringReduced(sym: Symbol, tp: Type): Unit = {
if (sym.isType && !sym.isAliasType && !sym.isClass) {
tp match {
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t2462c.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings
// scalac: -Werror
//

import annotation._
Expand Down
16 changes: 16 additions & 0 deletions test/files/neg/t5606.check
@@ -0,0 +1,16 @@
t5606.scala:3: error: identifier expected but '_' found.
case class CaseTest[_](someData: String)
^
t5606.scala:5: error: using `?` as a type name requires backticks.
case class CaseTest_?[?](someData: String)
^
t5606.scala:8: error: identifier expected but '_' found.
case class CaseTest2[_, _](someData: String)
^
t5606.scala:11: error: identifier expected but '_' found.
def f[_](x: Int) = ???
^
t5606.scala:23: error: using `?` as a type name requires backticks.
def regress_?[F[?]] = 2
^
5 errors
26 changes: 26 additions & 0 deletions test/files/neg/t5606.scala
@@ -0,0 +1,26 @@
// scalac: -Xsource:3
// was: _ taken as ident of type param, but poor interactions below
case class CaseTest[_](someData: String)

case class CaseTest_?[?](someData: String)

// was: _ already defined
case class CaseTest2[_, _](someData: String)

class C {
def f[_](x: Int) = ???
}

object Test extends App {
def f0 = new CaseTest("X")
def f1: CaseTest[Int] = new CaseTest[Int]("X") // OK!
def f2: CaseTest[Int] = CaseTest[Int]("X") // CaseTest[Any]
def f3 = new CaseTest[Int]("X").copy() // CaseTest[Any]
def f4 = new CaseTest[Int]("X").copy[Int]() // CaseTest[Any]

def regress0[F[_]] = 0
def regress1[F[_, _]] = 1
def regress_?[F[?]] = 2
//def regress0[F[_$$1]] = 0;
//def regress1[F[_$$2, _$$3]] = 1
}
15 changes: 15 additions & 0 deletions test/files/neg/t5606b.check
@@ -0,0 +1,15 @@
t5606b.scala:4: warning: Top-level wildcard is not allowed and will error under -Xsource:3
case class CaseTest[_](someData: String)
^
t5606b.scala:7: warning: Top-level wildcard is not allowed and will error under -Xsource:3
case class CaseTest2[_, _](someData: String)
^
t5606b.scala:7: warning: Top-level wildcard is not allowed and will error under -Xsource:3
case class CaseTest2[_, _](someData: String)
^
t5606b.scala:10: warning: Top-level wildcard is not allowed and will error under -Xsource:3
def f[_](x: Int) = ???
^
error: No warnings can be incurred under -Werror.
4 warnings
1 error
11 changes: 11 additions & 0 deletions test/files/neg/t5606b.scala
@@ -0,0 +1,11 @@
// scalac: -Xlint -Werror
//
// was: _ taken as ident of type param, now a fresh name
case class CaseTest[_](someData: String)

// was: _ already defined, now a fresh name
case class CaseTest2[_, _](someData: String)

class C {
def f[_](x: Int) = ???
}
8 changes: 1 addition & 7 deletions test/files/neg/trailing-commas.check
Expand Up @@ -61,15 +61,9 @@ trait TypeArgs { def f: C[Int, String, ] }
trailing-commas.scala:23: error: identifier expected but ']' found.
trait TypeParamClause { type C[A, B, ] }
^
trailing-commas.scala:23: error: ']' expected but '}' found.
trait TypeParamClause { type C[A, B, ] }
^
trailing-commas.scala:24: error: identifier expected but ']' found.
trait FunTypeParamClause { def f[A, B, ] }
^
trailing-commas.scala:24: error: ']' expected but '}' found.
trait FunTypeParamClause { def f[A, B, ] }
^
trailing-commas.scala:26: error: identifier expected but ')' found.
trait SimpleType { def f: (Int, String, ) }
^
Expand Down Expand Up @@ -127,4 +121,4 @@ trait SimpleType2 { def f: (Int, ) }
trailing-commas.scala:48: error: ')' expected but '}' found.
trait SimpleType2 { def f: (Int, ) }
^
43 errors
41 errors
14 changes: 7 additions & 7 deletions test/files/pos/t5606.scala
@@ -1,9 +1,9 @@
// was: _ taken as ident of type param, now a fresh name
case class CaseTest[_](someData: String)

// was: _ already defined, now a fresh name
case class CaseTest2[_, _](someData: String)







case class CaseTest[_](someData:String)
class C {
def f[_](x: Int) = ???
}

0 comments on commit 933b3c6

Please sign in to comment.