Skip to content

Commit afdda3b

Browse files
committed
Make deferred a method in the compiletime package
1 parent 1eb3458 commit afdda3b

File tree

12 files changed

+95
-22
lines changed

12 files changed

+95
-22
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ class Definitions {
240240
@tu lazy val Compiletime_codeOf: Symbol = CompiletimePackageClass.requiredMethod("codeOf")
241241
@tu lazy val Compiletime_erasedValue : Symbol = CompiletimePackageClass.requiredMethod("erasedValue")
242242
@tu lazy val Compiletime_uninitialized: Symbol = CompiletimePackageClass.requiredMethod("uninitialized")
243+
@tu lazy val Compiletime_deferred : Symbol = CompiletimePackageClass.requiredMethod("deferred")
243244
@tu lazy val Compiletime_error : Symbol = CompiletimePackageClass.requiredMethod(nme.error)
244245
@tu lazy val Compiletime_requireConst : Symbol = CompiletimePackageClass.requiredMethod("requireConst")
245246
@tu lazy val Compiletime_constValue : Symbol = CompiletimePackageClass.requiredMethod("constValue")

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,13 @@ object Erasure {
566566
case Some(annot) =>
567567
val message = annot.argumentConstant(0) match
568568
case Some(c) =>
569-
c.stringValue.toMessage
569+
val addendum = tree match
570+
case tree: RefTree
571+
if tree.symbol == defn.Compiletime_deferred && tree.name != nme.deferred =>
572+
i".\nNote that `deferred` can only be used under its own name when implementing a given in a trait; `${tree.name}` is not accepted."
573+
case _ =>
574+
""
575+
(c.stringValue ++ addendum).toMessage
570576
case _ =>
571577
em"""Reference to ${tree.symbol.showLocated} should not have survived,
572578
|it should have been processed and eliminated during expansion of an enclosing macro or term erasure."""

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,12 +1823,12 @@ class Namer { typer: Typer =>
18231823
// translate `given T = deferred` to an abstract given with HasDefault flag
18241824
if sym.is(Given) then
18251825
mdef.rhs match
1826-
case Ident(nme.deferred) if Feature.enabled(modularity) =>
1827-
if !sym.maybeOwner.is(Trait) then
1828-
report.error(em"`deferred` can only be used for givens in traits", mdef.rhs.srcPos)
1829-
else
1830-
sym.resetFlag(Final)
1831-
sym.setFlag(Deferred | HasDefault)
1826+
case rhs: RefTree
1827+
if rhs.name == nme.deferred
1828+
&& typedAheadExpr(rhs).symbol == defn.Compiletime_deferred
1829+
&& sym.maybeOwner.is(Trait) =>
1830+
sym.resetFlag(Final)
1831+
sym.setFlag(Deferred | HasDefault)
18321832
case _ =>
18331833

18341834
val mbrTpe = paramFn(checkSimpleKinded(typedAheadType(mdef.tpt, tptProto)).tpe)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ object RefChecks {
552552
overrideError("is an extension method, cannot override a normal method")
553553
else if (other.is(ExtensionMethod) && !member.is(ExtensionMethod)) // (1.3)
554554
overrideError("is a normal method, cannot override an extension method")
555-
else if !other.is(Deferred)
555+
else if (!other.is(Deferred) || other.isAllOf(Given | HasDefault))
556556
&& !member.is(Deferred)
557557
&& !other.name.is(DefaultGetterName)
558558
&& !member.isAnyOverride

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2852,20 +2852,32 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
28522852
val dcl = mbr.symbol
28532853
val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
28542854
val constr = cls.primaryConstructor
2855-
val paramScope = newScopeWith(cls.paramAccessors.filter(_.is(Given))*)
2855+
val usingParamAccessors = cls.paramAccessors.filter(_.is(Given))
2856+
val paramScope = newScopeWith(usingParamAccessors*)
28562857
val searchCtx = ctx.outer.fresh.setScope(paramScope)
28572858
val rhs = implicitArgTree(target, cdef.span,
28582859
where = i"inferring the implementation of the deferred ${dcl.showLocated}"
28592860
)(using searchCtx)
2861+
28602862
val impl = dcl.copy(cls,
2861-
flags = dcl.flags &~ (HasDefault | Deferred) | Final,
2863+
flags = dcl.flags &~ (HasDefault | Deferred) | Final | Override,
28622864
info = target,
28632865
coord = rhs.span).entered.asTerm
2864-
ValDef(impl, rhs)
2866+
2867+
def anchorParams = new TreeMap:
2868+
override def transform(tree: Tree)(using Context): Tree = tree match
2869+
case id: Ident if usingParamAccessors.contains(id.symbol) =>
2870+
cpy.Select(id)(This(cls), id.name)
2871+
case _ =>
2872+
super.transform(tree)
2873+
ValDef(impl, anchorParams.transform(rhs))
2874+
end givenImpl
28652875

28662876
val givenImpls =
28672877
cls.thisType.implicitMembers
2878+
//.showing(i"impl def givens for $cls/$result")
28682879
.filter(_.symbol.isAllOf(DeferredGivenFlags, butNot = Param))
2880+
//.showing(i"impl def filtered givens for $cls/$result")
28692881
.filter(isGivenValue)
28702882
.map(givenImpl)
28712883
body ++ givenImpls

library/src/scala/compiletime/package.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ def erasedValue[T]: T = erasedValue[T]
4242
@compileTimeOnly("`uninitialized` can only be used as the right hand side of a mutable field definition")
4343
def uninitialized: Nothing = ???
4444

45+
/** Used as the right hand side of a given in a trait, like this
46+
*
47+
* ```
48+
* given T = deferred
49+
* ```
50+
*
51+
* This signifies that the given will get a synthesized definition in all classes
52+
* that implement the enclosing trait and that do not contain an explicit overriding
53+
* definition of that given.
54+
*/
55+
@compileTimeOnly("`deferred` can only be used as the right hand side of a given definition in a trait")
56+
def deferred: Nothing = ???
57+
4558
/** The error method is used to produce user-defined compile errors during inline expansion.
4659
* If an inline expansion results in a call error(msgStr) the compiler produces an error message containing the given msgStr.
4760
*

tests/neg/deferred-givens.check

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +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
1+
-- [E172] Type Error: tests/neg/deferred-givens.scala:11:6 -------------------------------------------------------------
2+
11 |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:13:15 ------------------------------------------------------------
6+
13 |abstract class C extends A // error
77
|^^^^^^^^^^^^^^^^^^^^^^^^^^
88
|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
9+
-- Error: tests/neg/deferred-givens.scala:26:8 -------------------------------------------------------------------------
10+
26 | class E extends A2 // error, can't summon polymorphic given
1111
| ^^^^^^^^^^^^^^^^^^
1212
| Cannnot infer the implementation of the deferred given instance given_Ctx3_T in trait A2
1313
| since that given is parameterized. An implementing given needs to be written explicitly.

tests/neg/deferred-givens.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//> using options -language:experimental.modularity -source future
2+
import compiletime.deferred
3+
24
class Ctx
35
class Ctx2
46

tests/neg/deferredSummon.check

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- Error: tests/neg/deferredSummon.scala:4:26 --------------------------------------------------------------------------
2+
4 | given Int = compiletime.deferred // error
3+
| ^^^^^^^^^^^^^^^^^^^^
4+
| `deferred` can only be used as the right hand side of a given definition in a trait
5+
-- Error: tests/neg/deferredSummon.scala:7:26 --------------------------------------------------------------------------
6+
7 | given Int = compiletime.deferred // error
7+
| ^^^^^^^^^^^^^^^^^^^^
8+
| `deferred` can only be used as the right hand side of a given definition in a trait
9+
-- Error: tests/neg/deferredSummon.scala:12:16 -------------------------------------------------------------------------
10+
12 | given Int = deferred // error
11+
| ^^^^^^^^
12+
| `deferred` can only be used as the right hand side of a given definition in a trait
13+
-- Error: tests/neg/deferredSummon.scala:16:14 -------------------------------------------------------------------------
14+
16 | given Int = defered // error
15+
| ^^^^^^^
16+
|`deferred` can only be used as the right hand side of a given definition in a trait.
17+
|Note that `deferred` can only be used under its own name when implementing a given in a trait; `defered` is not accepted.

tests/neg/deferredSummon.scala

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

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

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

99
trait A:
10+
import compiletime.deferred
1011
locally:
1112
given Int = deferred // error
1213

14+
trait B:
15+
import compiletime.deferred as defered
16+
given Int = defered // error
17+
18+
19+

tests/pos/deferred-givens.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//> using options -language:experimental.modularity -source future
12
import compiletime.*
23
class Ord[Elem]
34

@@ -8,4 +9,16 @@ trait B:
89

910
class C extends B:
1011
type Elem = String
11-
given Ord[Elem] = ???
12+
override given Ord[Elem] = ???
13+
14+
def bar(using Ord[String]) = 1
15+
16+
class D(using Ord[String]) extends B:
17+
type Elem = String
18+
19+
class E(using x: Ord[String]) extends B:
20+
type Elem = String
21+
override given Ord[Elem] = x
22+
23+
class F[X: Ord] extends B:
24+
type Elem = X

tests/pos/deferredSummon.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//> using options -language:experimental.modularity -source future
2+
import compiletime.deferred
3+
24
trait Ord:
35
type Self
46
def less(x: Self, y: Self): Boolean

0 commit comments

Comments
 (0)