Skip to content

Commit f5ced11

Browse files
authored
Merge pull request #11862 from dotty-staging/fix-11859
Disallow context functions as case class elements
2 parents 0c4321a + b607817 commit f5ced11

File tree

10 files changed

+47
-45
lines changed

10 files changed

+47
-45
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
541541
// HKLambdas are hash-consed, need to create an artificial difference by adding
542542
// a LazyRef to a bound.
543543
val TypeBounds(lo, hi) :: pinfos1 = tl.paramInfos
544-
paramInfos = TypeBounds(lo, LazyRef(hi)) :: pinfos1
544+
paramInfos = TypeBounds(lo, LazyRef.of(hi)) :: pinfos1
545545
}
546546
ensureFresh(tl.newLikeThis(tl.paramNames, paramInfos, tl.resultType))
547547
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ class TypeApplications(val self: Type) extends AnyVal {
363363
case dealiased: TypeBounds =>
364364
dealiased.derivedTypeBounds(dealiased.lo.appliedTo(args), dealiased.hi.appliedTo(args))
365365
case dealiased: LazyRef =>
366-
LazyRef(dealiased.ref.appliedTo(args))
366+
LazyRef.of(dealiased.ref.appliedTo(args))
367367
case dealiased: WildcardType =>
368368
WildcardType(dealiased.optBounds.orElse(TypeBounds.empty).appliedTo(args).bounds)
369369
case dealiased: TypeRef if dealiased.symbol == defn.NothingClass =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -687,8 +687,8 @@ object TypeOps:
687687
tp // break cycles
688688

689689
case tp: TypeRef if !tp.symbol.isClass =>
690-
def lo = LazyRef(apply(tp.underlying.loBound))
691-
def hi = LazyRef(apply(tp.underlying.hiBound))
690+
def lo = LazyRef.of(apply(tp.underlying.loBound))
691+
def hi = LazyRef.of(apply(tp.underlying.hiBound))
692692
val lookup = boundTypeParams.lookup(tp)
693693
if lookup != null then lookup
694694
else

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2800,7 +2800,7 @@ object Types {
28002800
}
28012801
}
28022802

2803-
case class LazyRef(private var refFn: Context ?=> Type) extends UncachedProxyType with ValueType {
2803+
case class LazyRef(private var refFn: Context => Type) extends UncachedProxyType with ValueType {
28042804
private var myRef: Type = null
28052805
private var computed = false
28062806

@@ -2813,7 +2813,7 @@ object Types {
28132813
throw CyclicReference(NoDenotation)
28142814
else
28152815
computed = true
2816-
val result = refFn
2816+
val result = refFn(ctx)
28172817
refFn = null
28182818
if result != null then myRef = result
28192819
else assert(myRef != null) // must have been `update`d
@@ -2835,6 +2835,8 @@ object Types {
28352835
override def equals(other: Any): Boolean = this.eq(other.asInstanceOf[AnyRef])
28362836
override def hashCode: Int = System.identityHashCode(this)
28372837
}
2838+
object LazyRef:
2839+
def of(refFn: Context ?=> Type): LazyRef = LazyRef(refFn(using _))
28382840

28392841
// --- Refined Type and RecType ------------------------------------------------
28402842

@@ -4655,7 +4657,7 @@ object Types {
46554657
RefinedType(selfType, sym.name,
46564658
TypeAlias(
46574659
withMode(Mode.CheckCyclic)(
4658-
LazyRef(force))))
4660+
LazyRef.of(force))))
46594661
cinfo.selfInfo match
46604662
case self: Type =>
46614663
cinfo.derivedClassInfo(
@@ -5254,7 +5256,8 @@ object Types {
52545256
derivedSuperType(tp, this(thistp), this(supertp))
52555257

52565258
case tp: LazyRef =>
5257-
LazyRef { refCtx ?=>
5259+
LazyRef { refCtx =>
5260+
given Context = refCtx
52585261
val ref1 = tp.ref
52595262
if refCtx.runId == mapCtx.runId then this(ref1)
52605263
else // splice in new run into map context

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ object Checking {
301301
catch {
302302
case ex: CyclicReference =>
303303
report.debuglog(i"cycle detected for $tp, $nestedCycleOK, $cycleOK")
304-
if (cycleOK) LazyRef(tp)
304+
if (cycleOK) LazyRef.of(tp)
305305
else if (reportErrors) throw ex
306306
else tp
307307
}

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

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,22 +2151,32 @@ class Typer extends Namer
21512151
val rhsToInline = PrepareInlineable.wrapRHS(ddef, tpt1, rhs1)
21522152
PrepareInlineable.registerInlineInfo(sym, rhsToInline)
21532153

2154-
if (sym.isConstructor && !sym.isPrimaryConstructor) {
2155-
if (sym.targetName != sym.name)
2156-
report.error(em"@targetName annotation may not be used on a constructor", ddef.srcPos)
2157-
2158-
for params <- paramss1; param <- params do
2159-
checkRefsLegal(param, sym.owner, (name, sym) => sym.is(TypeParam), "secondary constructor")
2160-
2161-
def checkThisConstrCall(tree: Tree): Unit = tree match {
2162-
case app: Apply if untpd.isSelfConstrCall(app) =>
2163-
if (sym.span.exists && app.symbol.span.exists && sym.span.start <= app.symbol.span.start)
2164-
report.error("secondary constructor must call a preceding constructor", app.srcPos)
2165-
case Block(call :: _, _) => checkThisConstrCall(call)
2166-
case _ =>
2167-
}
2168-
checkThisConstrCall(rhs1)
2169-
}
2154+
if sym.isConstructor then
2155+
if sym.isPrimaryConstructor then
2156+
if sym.owner.is(Case) then
2157+
for
2158+
params <- paramss1.dropWhile(TypeDefs.unapply(_).isDefined).take(1)
2159+
case param: ValDef <- params
2160+
do
2161+
if defn.isContextFunctionType(param.tpt.tpe) then
2162+
report.error("case class element cannot be a context function", param.srcPos)
2163+
else
2164+
if sym.targetName != sym.name then
2165+
report.error(em"@targetName annotation may not be used on a constructor", ddef.srcPos)
2166+
2167+
for params <- paramss1; param <- params do
2168+
checkRefsLegal(param, sym.owner, (name, sym) => sym.is(TypeParam), "secondary constructor")
2169+
2170+
def checkThisConstrCall(tree: Tree): Unit = tree match
2171+
case app: Apply if untpd.isSelfConstrCall(app) =>
2172+
if (sym.span.exists && app.symbol.span.exists && sym.span.start <= app.symbol.span.start)
2173+
report.error("secondary constructor must call a preceding constructor", app.srcPos)
2174+
case Block(call :: _, _) => checkThisConstrCall(call)
2175+
case _ =>
2176+
2177+
checkThisConstrCall(rhs1)
2178+
end if
2179+
end if
21702180

21712181
if sym.is(Method) && sym.owner.denot.isRefinementClass then
21722182
for annot <- sym.paramSymss.flatten.filter(_.isTerm).flatMap(_.getAnnotation(defn.ImplicitNotFoundAnnot)) do

tests/neg/i11859.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class I
2+
case class C(x: I ?=> Object) // error: case class element cannot be a context function
3+
4+
type ITO = I ?=> Object
5+
case class D(x: ITO) // error: case class element cannot be a context function
6+
7+
@main def Test =
8+
val c = C(new Object())
9+
assert(c.hashCode == c.hashCode())

tests/pos/case-getters.scala

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/pos/i11350.scala

Lines changed: 0 additions & 5 deletions
This file was deleted.

tests/pos/i7778.scala

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)