Skip to content

Commit 62d08e3

Browse files
committed
Rename deferredSummon to deferred and allow it for defs
The idea is that `given ... = deferred` should be the new syntax for abstract givens. These can only be defined in traits and need to be implemented in the first subclass extending the trait. If the definition of a given vals is missing, one is synthesized by an implicit search at the site of the extending class. This will free the syntax given A is TC for the more common case where we just want to implement a marker type class TC. Also allow # Conflicts: # compiler/src/dotty/tools/dotc/typer/Namer.scala
1 parent 7b51c58 commit 62d08e3

File tree

8 files changed

+75
-17
lines changed

8 files changed

+75
-17
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ object StdNames {
453453
val create: N = "create"
454454
val currentMirror: N = "currentMirror"
455455
val curried: N = "curried"
456-
val deferredSummon: N = "deferredSummon"
456+
val deferred: N = "deferred"
457457
val definitions: N = "definitions"
458458
val delayedInit: N = "delayedInit"
459459
val delayedInitArg: N = "delayedInit$body"

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,10 +922,10 @@ trait Implicits:
922922

923923

924924
/** Search an implicit argument and report error if not found */
925-
def implicitArgTree(formal: Type, span: Span)(using Context): Tree = {
925+
def implicitArgTree(formal: Type, span: Span, where: => String = "")(using Context): Tree = {
926926
val arg = inferImplicitArg(formal, span)
927927
if (arg.tpe.isInstanceOf[SearchFailureType])
928-
report.error(missingArgMsg(arg, formal, ""), ctx.source.atSpan(span))
928+
report.error(missingArgMsg(arg, formal, where), ctx.source.atSpan(span))
929929
arg
930930
}
931931

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,12 +1806,12 @@ class Namer { typer: Typer =>
18061806
WildcardType
18071807
}
18081808

1809-
// translate `given T = deferredSummon` to an abstract given with HasDefault flag
1810-
if sym.is(Given, butNot = Method) then
1809+
// translate `given T = deferred` to an abstract given with HasDefault flag
1810+
if sym.is(Given) then
18111811
mdef.rhs match
1812-
case Ident(nme.deferredSummon) if Feature.enabled(modularity) =>
1812+
case Ident(nme.deferred) if Feature.enabled(modularity) =>
18131813
if !sym.maybeOwner.is(Trait) then
1814-
report.error(em"`deferredSummon` can only be used for givens in traits", mdef.rhs.srcPos)
1814+
report.error(em"`deferred` can only be used for givens in traits", mdef.rhs.srcPos)
18151815
else
18161816
sym.resetFlag(Final | Lazy)
18171817
sym.setFlag(Deferred | HasDefault)

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

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,7 +2579,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25792579
val rhs1 = vdef.rhs match {
25802580
case rhs @ Ident(nme.WILDCARD) =>
25812581
rhs.withType(tpt1.tpe)
2582-
case Ident(nme.deferredSummon) if sym.isAllOf(DeferredGivenFlags, butNot = Param) =>
2582+
case Ident(nme.deferred) if sym.isAllOf(DeferredGivenFlags, butNot = Param) =>
25832583
EmptyTree
25842584
case rhs =>
25852585
typedExpr(rhs, tpt1.tpe.widenExpr)
@@ -2643,9 +2643,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26432643

26442644
if sym.isInlineMethod then rhsCtx.addMode(Mode.InlineableBody)
26452645
if sym.is(ExtensionMethod) then rhsCtx.addMode(Mode.InExtensionMethod)
2646-
val rhs1 = PrepareInlineable.dropInlineIfError(sym,
2647-
if sym.isScala2Macro then typedScala2MacroBody(ddef.rhs)(using rhsCtx)
2648-
else typedExpr(ddef.rhs, tpt1.tpe.widenExpr)(using rhsCtx))
2646+
val rhs1 = ddef.rhs match
2647+
case Ident(nme.deferred) if sym.isAllOf(DeferredGivenFlags) =>
2648+
EmptyTree
2649+
case rhs =>
2650+
PrepareInlineable.dropInlineIfError(sym,
2651+
if sym.isScala2Macro then typedScala2MacroBody(ddef.rhs)(using rhsCtx)
2652+
else typedExpr(ddef.rhs, tpt1.tpe.widenExpr)(using rhsCtx))
26492653

26502654
if sym.isInlineMethod then
26512655
if StagingLevel.level > 0 then
@@ -2826,21 +2830,33 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
28262830
case None =>
28272831
body
28282832

2829-
/** Implement givens that were declared with a `deferredSummon` rhs.
2833+
/** Implement givens that were declared with a `deferred` rhs.
28302834
* The a given value matching the declared type is searched in a
28312835
* context directly enclosing the current class, in which all given
28322836
* parameters of the current class are also defined.
28332837
*/
28342838
def implementDeferredGivens(body: List[Tree]): List[Tree] =
28352839
if cls.is(Trait) then body
28362840
else
2841+
def isGivenValue(mbr: TermRef) =
2842+
val dcl = mbr.symbol
2843+
if dcl.is(Method) then
2844+
report.error(
2845+
em"""Cannnot infer the implementation of the deferred ${dcl.showLocated}
2846+
|since that given is parameterized. An implementing given needs to be written explicitly.""",
2847+
cdef.srcPos)
2848+
false
2849+
else true
2850+
28372851
def givenImpl(mbr: TermRef): ValDef =
28382852
val dcl = mbr.symbol
28392853
val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
28402854
val constr = cls.primaryConstructor
28412855
val paramScope = newScopeWith(cls.paramAccessors.filter(_.is(Given))*)
28422856
val searchCtx = ctx.outer.fresh.setScope(paramScope)
2843-
val rhs = implicitArgTree(target, cdef.span)(using searchCtx)
2857+
val rhs = implicitArgTree(target, cdef.span,
2858+
where = i"inferring the implementation of the deferred ${dcl.showLocated}"
2859+
)(using searchCtx)
28442860
val impl = dcl.copy(cls,
28452861
flags = dcl.flags &~ (HasDefault | Deferred) | Final,
28462862
info = target,
@@ -2850,6 +2866,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
28502866
val givenImpls =
28512867
cls.thisType.implicitMembers
28522868
.filter(_.symbol.isAllOf(DeferredGivenFlags, butNot = Param))
2869+
.filter(isGivenValue)
28532870
.map(givenImpl)
28542871
body ++ givenImpls
28552872
end implementDeferredGivens

tests/neg/deferred-givens.check

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- [E172] Type Error: tests/neg/deferred-givens.scala:9:6 --------------------------------------------------------------
2+
9 |class B extends A // error
3+
|^^^^^^^^^^^^^^^^^
4+
|No given instance of type Ctx was found for inferring the implementation of the deferred given instance ctx in trait A
5+
-- [E172] Type Error: tests/neg/deferred-givens.scala:11:15 ------------------------------------------------------------
6+
11 |abstract class C extends A // error
7+
|^^^^^^^^^^^^^^^^^^^^^^^^^^
8+
|No given instance of type Ctx was found for inferring the implementation of the deferred given instance ctx in trait A
9+
-- Error: tests/neg/deferred-givens.scala:24:8 -------------------------------------------------------------------------
10+
24 | class E extends A2 // error, can't summon polymorphic given
11+
| ^^^^^^^^^^^^^^^^^^
12+
| Cannnot infer the implementation of the deferred given instance given_Ctx3_T in trait A2
13+
| since that given is parameterized. An implementing given needs to be written explicitly.

tests/neg/deferred-givens.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//> using options -YXtypeclass -source future
2+
class Ctx
3+
class Ctx2
4+
5+
trait A:
6+
given Ctx as ctx = deferred
7+
given Ctx2 = deferred
8+
9+
class B extends A // error
10+
11+
abstract class C extends A // error
12+
13+
class D extends A:
14+
given Ctx as ctx = Ctx() // ok, was implemented
15+
given Ctx2 = Ctx2() // ok
16+
17+
class Ctx3[T]
18+
19+
trait A2:
20+
given [T] => Ctx3[T] = deferred
21+
22+
object O:
23+
given [T] => Ctx3[T] = Ctx3[T]()
24+
class E extends A2 // error, can't summon polymorphic given
25+
26+
class E extends A2:
27+
given [T] => Ctx3[T] = Ctx3[T]() // ok
28+

tests/neg/deferredSummon.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//> using options -language:experimental.modularity
22

33
object Test:
4-
given Int = deferredSummon // error
4+
given Int = deferred // error
55

66
abstract class C:
7-
given Int = deferredSummon // error
7+
given Int = deferred // error
88

99
trait A:
1010
locally:
11-
given Int = deferredSummon // error
11+
given Int = deferred // error
1212

tests/pos/deferredSummon.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ trait Ord:
55

66
trait A:
77
type Elem
8-
given Elem is Ord = deferredSummon
8+
given Elem is Ord = deferred
99
def foo = summon[Elem is Ord]
1010

1111
trait B:

0 commit comments

Comments
 (0)