Skip to content

Commit a10a271

Browse files
smarterKordyjan
authored andcommitted
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. [Cherry-picked 77be114]
1 parent 250f806 commit a10a271

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}
@@ -202,10 +202,14 @@ object desugar {
202202
else vdef1
203203
end valDef
204204

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

@@ -243,7 +247,9 @@ object desugar {
243247
case ContextBounds(tbounds, cxbounds) =>
244248
val iflag = if sourceVersion.isAtLeast(`future`) then Given else Implicit
245249
evidenceParamBuf ++= makeImplicitParameters(
246-
cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor)
250+
cxbounds, iflag,
251+
mkParamName = () => ContextBoundParamName.fresh(),
252+
forPrimaryConstructor = isPrimaryConstructor)
247253
tbounds
248254
case LambdaTypeTree(tparams, body) =>
249255
cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body))
@@ -380,11 +386,11 @@ object desugar {
380386
meth.paramss :+ evidenceParams
381387
cpy.DefDef(meth)(paramss = paramss1)
382388

383-
/** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */
389+
/** The parameters generated from the contextual bounds of `meth`, as generated by `desugar.defDef` */
384390
private def evidenceParams(meth: DefDef)(using Context): List[ValDef] =
385391
meth.paramss.reverse match {
386392
case ValDefs(vparams @ (vparam :: _)) :: _ if vparam.mods.isOneOf(GivenOrImplicit) =>
387-
vparams.takeWhile(_.name.is(EvidenceParamName))
393+
vparams.takeWhile(_.name.is(ContextBoundParamName))
388394
case _ =>
389395
Nil
390396
}
@@ -1500,7 +1506,7 @@ object desugar {
15001506

15011507
def makeContextualFunction(formals: List[Tree], body: Tree, erasedParams: List[Boolean])(using Context): Function = {
15021508
val mods = Given
1503-
val params = makeImplicitParameters(formals, mods)
1509+
val params = makeImplicitParameters(formals, mods, mkParamName = () => ContextFunctionParamName.fresh())
15041510
FunctionWithMods(params, body, Modifiers(mods), erasedParams)
15051511
}
15061512

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._
@@ -975,7 +975,7 @@ trait Implicits:
975975
def addendum = if (qt1 eq qt) "" else (i"\nWhere $qt is an alias of: $qt1")
976976
i"parameter of ${qual.tpe.widen}$addendum"
977977
case _ =>
978-
i"${ if paramName.is(EvidenceParamName) then "an implicit parameter"
978+
i"${ if paramName.is(ContextBoundParamName) then "a context parameter"
979979
else s"parameter $paramName" } of $methodStr"
980980
}
981981

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,8 +1686,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
16861686
checkInInlineContext("summonFrom", tree.srcPos)
16871687
val cases1 = tree.cases.mapconserve {
16881688
case cdef @ CaseDef(pat @ Typed(Ident(nme.WILDCARD), _), _, _) =>
1689-
// case _ : T --> case evidence$n : T
1690-
cpy.CaseDef(cdef)(pat = untpd.Bind(EvidenceParamName.fresh(), pat))
1689+
// case _ : T --> case _$n : T
1690+
cpy.CaseDef(cdef)(pat = untpd.Bind(WildcardParamName.fresh(), pat))
16911691
case cdef => cdef
16921692
}
16931693
typedMatchFinish(tree, tpd.EmptyTree, defn.ImplicitScrutineeTypeRef, cases1, pt)
@@ -1962,7 +1962,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
19621962
def addCanThrowCapabilities(expr: untpd.Tree, cases: List[CaseDef])(using Context): untpd.Tree =
19631963
def makeCanThrow(tp: Type): untpd.Tree =
19641964
untpd.ValDef(
1965-
EvidenceParamName.fresh(),
1965+
CanThrowEvidenceName.fresh(),
19661966
untpd.TypeTree(defn.CanThrowClass.typeRef.appliedTo(tp)),
19671967
untpd.ref(defn.Compiletime_erasedValue))
19681968
.withFlags(Given | Final | Erased)
@@ -3686,7 +3686,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
36863686
else tree
36873687
else if wtp.isContextualMethod then
36883688
def isContextBoundParams = wtp.stripPoly match
3689-
case MethodType(EvidenceParamName(_) :: _) => true
3689+
case MethodType(ContextBoundParamName(_) :: _) => true
36903690
case _ => false
36913691
if sourceVersion == `future-migration` && isContextBoundParams && pt.args.nonEmpty
36923692
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)