Skip to content

Commit 77be114

Browse files
committed
Use a specific NameKind for context bounds
There are various places in the compiler and assorted tools where we assume that an EvidenceParamName is the name of a context bound, but in practice we also used the same NameKind in other cases such as for inferred contextual functions. This commit cleans things up by replacing EvidenceParamName by: - ContextBoundParamName - ContextFunctionParamName - CanThrowEvidenceParamName - and the existing WildcardParamName Note that Scala 2 also uses "evidence$" prefixes to represent context bounds, this is why some pretty-printing code that aims to resugar context bounds coming from both Scala 2 and 3 does a syntactic check for `ContextBoundParamName.separator` instead of a semantic check on the NameKind itself, this could perhaps be handled in a nicer way using unmangle in the Scala2Unpickler.
1 parent ce1ce99 commit 77be114

File tree

16 files changed

+66
-37
lines changed

16 files changed

+66
-37
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import util.Spans._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags
77
import Symbols._, StdNames._, Trees._, ContextOps._
88
import Decorators._, transform.SymUtils._
99
import Annotations.Annotation
10-
import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName, WildcardParamName}
10+
import NameKinds.{UniqueName, ContextBoundParamName, ContextFunctionParamName, DefaultGetterName, WildcardParamName}
1111
import typer.{Namer, Checking}
1212
import util.{Property, SourceFile, SourcePosition, Chars}
1313
import config.Feature.{sourceVersion, migrateTo3, enabled}
@@ -203,10 +203,14 @@ object desugar {
203203
else vdef1
204204
end valDef
205205

206-
def makeImplicitParameters(tpts: List[Tree], implicitFlag: FlagSet, forPrimaryConstructor: Boolean = false)(using Context): List[ValDef] =
207-
for (tpt <- tpts) yield {
206+
def makeImplicitParameters(
207+
tpts: List[Tree], implicitFlag: FlagSet,
208+
mkParamName: () => TermName,
209+
forPrimaryConstructor: Boolean = false
210+
)(using Context): List[ValDef] =
211+
for (tpt, i) <- tpts.zipWithIndex yield {
208212
val paramFlags: FlagSet = if (forPrimaryConstructor) LocalParamAccessor else Param
209-
val epname = EvidenceParamName.fresh()
213+
val epname = mkParamName()
210214
ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | implicitFlag)
211215
}
212216

@@ -244,7 +248,9 @@ object desugar {
244248
case ContextBounds(tbounds, cxbounds) =>
245249
val iflag = if sourceVersion.isAtLeast(`future`) then Given else Implicit
246250
evidenceParamBuf ++= makeImplicitParameters(
247-
cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor)
251+
cxbounds, iflag,
252+
mkParamName = () => ContextBoundParamName.fresh(),
253+
forPrimaryConstructor = isPrimaryConstructor)
248254
tbounds
249255
case LambdaTypeTree(tparams, body) =>
250256
cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body))
@@ -406,11 +412,11 @@ object desugar {
406412
meth.paramss :+ evidenceParams
407413
cpy.DefDef(meth)(paramss = paramss1)
408414

409-
/** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */
415+
/** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
410416
private def evidenceParams(meth: DefDef)(using Context): List[ValDef] =
411417
meth.paramss.reverse match {
412418
case ValDefs(vparams @ (vparam :: _)) :: _ if vparam.mods.isOneOf(GivenOrImplicit) =>
413-
vparams.takeWhile(_.name.is(EvidenceParamName))
419+
vparams.takeWhile(_.name.is(ContextBoundParamName))
414420
case _ =>
415421
Nil
416422
}
@@ -1585,7 +1591,7 @@ object desugar {
15851591

15861592
def makeContextualFunction(formals: List[Tree], body: Tree, erasedParams: List[Boolean])(using Context): Function = {
15871593
val mods = Given
1588-
val params = makeImplicitParameters(formals, mods)
1594+
val params = makeImplicitParameters(formals, mods, mkParamName = () => ContextFunctionParamName.fresh())
15891595
FunctionWithMods(params, body, Modifiers(mods), erasedParams)
15901596
}
15911597

compiler/src/dotty/tools/dotc/core/NameKinds.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,31 @@ object NameKinds {
278278
if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info)
279279
}
280280

281+
/** The name of the term parameter generated for a context bound:
282+
*
283+
* def foo[T: A](...): ...
284+
*
285+
* becomes:
286+
*
287+
* def foo[T](...)(using evidence$1: A[T]): ...
288+
*
289+
* The "evidence$" prefix is a convention copied from Scala 2.
290+
*/
291+
val ContextBoundParamName: UniqueNameKind = new UniqueNameKind("evidence$")
292+
293+
/** The name of an inferred contextual function parameter:
294+
*
295+
* val x: A ?=> B = b
296+
*
297+
* becomes:
298+
*
299+
* val x: A ?=> B = (contextual$1: A) ?=> b
300+
*/
301+
val ContextFunctionParamName: UniqueNameKind = new UniqueNameKind("contextual$")
302+
281303
/** Other unique names */
304+
val CanThrowEvidenceName: UniqueNameKind = new UniqueNameKind("canThrow$")
282305
val TempResultName: UniqueNameKind = new UniqueNameKind("ev$")
283-
val EvidenceParamName: UniqueNameKind = new UniqueNameKind("evidence$")
284306
val DepParamName: UniqueNameKind = new UniqueNameKind("(param)")
285307
val LazyImplicitName: UniqueNameKind = new UniqueNameKind("$_lazy_implicit_$")
286308
val LazyLocalName: UniqueNameKind = new UniqueNameKind("$lzy")

compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ object Scala3:
216216

217217
def isEmptyNumbered: Boolean =
218218
!name.is(NameKinds.WildcardParamName)
219-
&& !name.is(NameKinds.EvidenceParamName)
219+
&& !name.is(NameKinds.ContextBoundParamName)
220+
&& !name.is(NameKinds.ContextFunctionParamName)
220221
&& { name match
221222
case NameKinds.AnyNumberedName(nme.EMPTY, _) => true
222223
case _ => false

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Contexts._
1313
import Types._
1414
import Flags._
1515
import Mode.ImplicitsEnabled
16-
import NameKinds.{LazyImplicitName, EvidenceParamName}
16+
import NameKinds.{LazyImplicitName, ContextBoundParamName}
1717
import Symbols._
1818
import Types._
1919
import Decorators._
@@ -993,7 +993,7 @@ trait Implicits:
993993
def addendum = if (qt1 eq qt) "" else (i"\nWhere $qt is an alias of: $qt1")
994994
i"parameter of ${qual.tpe.widen}$addendum"
995995
case _ =>
996-
i"${ if paramName.is(EvidenceParamName) then "an implicit parameter"
996+
i"${ if paramName.is(ContextBoundParamName) then "a context parameter"
997997
else s"parameter $paramName" } of $methodStr"
998998
}
999999

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,8 +1734,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
17341734
checkInInlineContext("summonFrom", tree.srcPos)
17351735
val cases1 = tree.cases.mapconserve {
17361736
case cdef @ CaseDef(pat @ Typed(Ident(nme.WILDCARD), _), _, _) =>
1737-
// case _ : T --> case evidence$n : T
1738-
cpy.CaseDef(cdef)(pat = untpd.Bind(EvidenceParamName.fresh(), pat))
1737+
// case _ : T --> case _$n : T
1738+
cpy.CaseDef(cdef)(pat = untpd.Bind(WildcardParamName.fresh(), pat))
17391739
case cdef => cdef
17401740
}
17411741
typedMatchFinish(tree, tpd.EmptyTree, defn.ImplicitScrutineeTypeRef, cases1, pt)
@@ -2010,7 +2010,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
20102010
def addCanThrowCapabilities(expr: untpd.Tree, cases: List[CaseDef])(using Context): untpd.Tree =
20112011
def makeCanThrow(tp: Type): untpd.Tree =
20122012
untpd.ValDef(
2013-
EvidenceParamName.fresh(),
2013+
CanThrowEvidenceName.fresh(),
20142014
untpd.TypeTree(defn.CanThrowClass.typeRef.appliedTo(tp)),
20152015
untpd.ref(defn.Compiletime_erasedValue))
20162016
.withFlags(Given | Final | Erased)
@@ -3756,7 +3756,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
37563756
else tree
37573757
else if wtp.isContextualMethod then
37583758
def isContextBoundParams = wtp.stripPoly match
3759-
case MethodType(EvidenceParamName(_) :: _) => true
3759+
case MethodType(ContextBoundParamName(_) :: _) => true
37603760
case _ => false
37613761
if sourceVersion == `future-migration` && isContextBoundParams && pt.args.nonEmpty
37623762
then // Under future-migration, don't infer implicit arguments yet for parameters

compiler/src/dotty/tools/dotc/util/Signatures.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ object Signatures {
407407
(params :: rest)
408408

409409
def isSyntheticEvidence(name: String) =
410-
if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else
410+
if !name.startsWith(NameKinds.ContextBoundParamName.separator) then false else
411411
symbol.paramSymss.flatten.find(_.name.show == name).exists(_.flags.is(Flags.Implicit))
412412

413413
denot.info.stripPoly match

presentation-compiler/src/main/dotty/tools/pc/completions/ScaladocCompletions.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ object ScaladocCompletions:
112112
defdef.trailingParamss.flatten.collect {
113113
case param
114114
if !param.symbol.isOneOf(Synthetic) &&
115-
!param.name.is(EvidenceParamName) &&
115+
!param.name.is(ContextBoundParamName) &&
116116
param.symbol != extensionParam =>
117117
param.name.show
118118
}
@@ -121,7 +121,7 @@ object ScaladocCompletions:
121121
case param
122122
if !param.is(Synthetic) &&
123123
!param.isTypeParam &&
124-
!param.name.is(EvidenceParamName) =>
124+
!param.name.is(ContextBoundParamName) =>
125125
param.name.show
126126
}
127127
case other =>

presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import scala.meta.pc.SymbolSearch
99
import dotty.tools.dotc.core.Contexts.Context
1010
import dotty.tools.dotc.core.Flags
1111
import dotty.tools.dotc.core.Flags.*
12-
import dotty.tools.dotc.core.NameKinds.EvidenceParamName
12+
import dotty.tools.dotc.core.NameKinds.ContextBoundParamName
1313
import dotty.tools.dotc.core.NameOps.*
1414
import dotty.tools.dotc.core.Names
1515
import dotty.tools.dotc.core.Names.Name
@@ -270,7 +270,7 @@ class ShortenedTypePrinter(
270270

271271
lazy val implicitEvidenceParams: Set[Symbol] =
272272
implicitParams
273-
.filter(p => p.name.toString.startsWith(EvidenceParamName.separator))
273+
.filter(p => p.name.toString.startsWith(ContextBoundParamName.separator))
274274
.toSet
275275

276276
lazy val implicitEvidencesByTypeParam: Map[Symbol, List[String]] =

scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ trait ClassLikeSupport:
578578
val baseTypeRepr = typeForClass(c).memberType(symbol)
579579

580580
def isSyntheticEvidence(name: String) =
581-
if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else
581+
if !name.startsWith(NameKinds.ContextBoundParamName.separator) then false else
582582
// This assumes that every parameter that starts with `evidence$` and is implicit is generated by compiler to desugar context bound.
583583
// Howrever, this is just a heuristic, so
584584
// `def foo[A](evidence$1: ClassTag[A]) = 1`

tests/neg/i11350.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
-- [E081] Type Error: tests/neg/i11350.scala:1:39 ----------------------------------------------------------------------
22
1 |class A1[T](action: A1[T] ?=> String = "") // error
33
| ^
4-
| Could not infer type for parameter evidence$1 of anonymous function
4+
| Could not infer type for parameter contextual$1 of anonymous function
55
|
66
| Partially inferred type for the parameter: A1[<?>]
77
|
88
| Expected type for the whole anonymous function: (A1[<?>]) ?=> String
99
-- [E081] Type Error: tests/neg/i11350.scala:2:39 ----------------------------------------------------------------------
1010
2 |class A2[T](action: A1[T] ?=> String = summon[A1[T]]) // error
1111
| ^
12-
| Could not infer type for parameter evidence$2 of anonymous function
12+
| Could not infer type for parameter contextual$2 of anonymous function
1313
|
1414
| Partially inferred type for the parameter: A1[<?>]
1515
|

tests/neg/missing-implicit1.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
-- [E172] Type Error: tests/neg/missing-implicit1.scala:23:42 ----------------------------------------------------------
2020
23 | List(1, 2, 3).traverse(x => Option(x)) // error
2121
| ^
22-
|No given instance of type testObjectInstance.Zip[Option] was found for an implicit parameter of method traverse in trait Traverse
22+
|No given instance of type testObjectInstance.Zip[Option] was found for a context parameter of method traverse in trait Traverse
2323
|
2424
|The following import might fix the problem:
2525
|

tests/neg/missing-implicit3.check

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
-- [E172] Type Error: tests/neg/missing-implicit3.scala:13:36 ----------------------------------------------------------
22
13 |val sortedFoos = sort(List(new Foo)) // error
33
| ^
4-
| No given instance of type ord.Ord[ord.Foo] was found for an implicit parameter of method sort in package ord.
5-
| I found:
4+
| No given instance of type ord.Ord[ord.Foo] was found for a context parameter of method sort in package ord.
5+
| I found:
66
|
7-
| ord.Ord.ordered[ord.Foo](/* missing */summon[ord.Foo => Comparable[? >: ord.Foo]])
7+
| ord.Ord.ordered[ord.Foo](/* missing */summon[ord.Foo => Comparable[? >: ord.Foo]])
88
|
9-
| But no implicit values were found that match type ord.Foo => Comparable[? >: ord.Foo].
9+
| But no implicit values were found that match type ord.Foo => Comparable[? >: ord.Foo].
1010
|
11-
| The following import might make progress towards fixing the problem:
11+
| The following import might make progress towards fixing the problem:
1212
|
13-
| import scala.math.Ordered.orderingToOrdered
13+
| import scala.math.Ordered.orderingToOrdered
1414
|

tests/neg/missing-implicit4.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
-- [E172] Type Error: tests/neg/missing-implicit4.scala:20:42 ----------------------------------------------------------
2020
20 | List(1, 2, 3).traverse(x => Option(x)) // error
2121
| ^
22-
| No given instance of type Zip[Option] was found for an implicit parameter of method traverse in trait Traverse
22+
| No given instance of type Zip[Option] was found for a context parameter of method traverse in trait Traverse
2323
|
24-
| The following import might fix the problem:
24+
| The following import might fix the problem:
2525
|
26-
| import instances.zipOption
26+
| import instances.zipOption
2727
|

tests/run-staging/multi-staging.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
stage1 code: ((q1: scala.quoted.Quotes) ?=> {
22
val x1: scala.Int = 2
3-
scala.quoted.runtime.Expr.quote[scala.Int](1.+(scala.quoted.runtime.Expr.splice[scala.Int](((evidence$5: scala.quoted.Quotes) ?=> scala.quoted.Expr.apply[scala.Int](x1)(scala.quoted.ToExpr.IntToExpr[scala.Int])(evidence$5))))).apply(using q1)
3+
scala.quoted.runtime.Expr.quote[scala.Int](1.+(scala.quoted.runtime.Expr.splice[scala.Int](((contextual$5: scala.quoted.Quotes) ?=> scala.quoted.Expr.apply[scala.Int](x1)(scala.quoted.ToExpr.IntToExpr[scala.Int])(contextual$5))))).apply(using q1)
44
})
55
3
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
((q: scala.quoted.Quotes) ?=> {
22
val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q)
3-
((evidence$2: scala.quoted.Quotes) ?=> a).apply(using q)
3+
((contextual$2: scala.quoted.Quotes) ?=> a).apply(using q)
44
})
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
((q: scala.quoted.Quotes) ?=> {
22
val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q)
3-
((q2: scala.quoted.Quotes) ?=> ((evidence$2: scala.quoted.Quotes) ?=> a).apply(using q2))
3+
((q2: scala.quoted.Quotes) ?=> ((contextual$2: scala.quoted.Quotes) ?=> a).apply(using q2))
44
}.apply(using q))

0 commit comments

Comments
 (0)