Skip to content

Commit 16b756c

Browse files
oderskytgodzik
authored andcommitted
Fix this references everywhere in dependent function types
We did fix them in parameters of dependent function types, but not in the result type. This led to a this reference being seen incorrectly as referring to the dependent function type itself. Fixes scala#23111 [Cherry-picked 068d9bb]
1 parent 075cddd commit 16b756c

File tree

3 files changed

+38
-23
lines changed

3 files changed

+38
-23
lines changed

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

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,11 +1451,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14511451
else typedFunctionValue(tree, pt)
14521452

14531453
def typedFunctionType(tree: untpd.Function, pt: Type)(using Context): Tree = {
1454-
val untpd.Function(args, body) = tree
1455-
body match
1456-
case untpd.CapturesAndResult(refs, result) =>
1454+
val untpd.Function(args, result) = tree
1455+
result match
1456+
case untpd.CapturesAndResult(refs, result1) =>
14571457
return typedUnadapted(untpd.makeRetaining(
1458-
cpy.Function(tree)(args, result), refs, tpnme.retains), pt)
1458+
cpy.Function(tree)(args, result1), refs, tpnme.retains), pt)
14591459
case _ =>
14601460
var (funFlags, erasedParams) = tree match {
14611461
case tree: untpd.FunctionWithMods => (tree.mods.flags, tree.erasedParams)
@@ -1467,37 +1467,28 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14671467
val isImpure = funFlags.is(Impure)
14681468

14691469
/** Typechecks dependent function type with given parameters `params` */
1470-
def typedDependent(params: List[untpd.ValDef])(using Context): Tree =
1471-
val fixThis = new untpd.UntypedTreeMap:
1472-
// pretype all references of this in outer context,
1473-
// so that they do not refer to the refined type being constructed
1474-
override def transform(tree: untpd.Tree)(using Context): untpd.Tree = tree match
1475-
case This(id) => untpd.TypedSplice(typedExpr(tree)(using ctx.outer))
1476-
case _ => super.transform(tree)
1477-
1470+
def typedDependent(params: List[untpd.ValDef], result: untpd.Tree)(using Context): Tree =
14781471
val params1 =
14791472
if funFlags.is(Given) then params.map(_.withAddedFlags(Given))
14801473
else params
1481-
val params2 = params1.map(fixThis.transformSub)
1482-
val params3 = params2.zipWithConserve(erasedParams) { (arg, isErased) =>
1474+
val params2 = params1.zipWithConserve(erasedParams): (arg, isErased) =>
14831475
if isErased then arg.withAddedFlags(Erased) else arg
1484-
}
1485-
val appDef0 = untpd.DefDef(nme.apply, List(params3), body, EmptyTree).withSpan(tree.span)
1476+
val appDef0 = untpd.DefDef(nme.apply, List(params2), result, EmptyTree).withSpan(tree.span)
14861477
index(appDef0 :: Nil)
14871478
val appDef = typed(appDef0).asInstanceOf[DefDef]
14881479
val mt = appDef.symbol.info.asInstanceOf[MethodType]
14891480
if (mt.isParamDependent)
14901481
report.error(em"$mt is an illegal function type because it has inter-parameter dependencies", tree.srcPos)
14911482
// Restart typechecking if there are erased classes that we want to mark erased
14921483
if mt.erasedParams.zip(mt.paramInfos.map(_.isErasedClass)).exists((paramErased, classErased) => classErased && !paramErased) then
1493-
val newParams = params3.zipWithConserve(mt.paramInfos.map(_.isErasedClass)) { (arg, isErasedClass) =>
1484+
val newParams = params2.zipWithConserve(mt.paramInfos.map(_.isErasedClass)) { (arg, isErasedClass) =>
14941485
if isErasedClass then arg.withAddedFlags(Erased) else arg
14951486
}
1496-
return typedDependent(newParams)
1487+
return typedDependent(newParams, result)
14971488
val core =
14981489
if mt.hasErasedParams then TypeTree(defn.ErasedFunctionClass.typeRef)
14991490
else
1500-
val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(body.span)
1491+
val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(result.span)
15011492
val paramTpts = appDef.termParamss.head.map(p => TypeTree(p.tpt.tpe).withSpan(p.tpt.span))
15021493
val funSym = defn.FunctionSymbol(numArgs, isContextual, isImpure)
15031494
val tycon = TypeTree(funSym.typeRef)
@@ -1507,19 +1498,28 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
15071498

15081499
args match {
15091500
case ValDef(_, _, _) :: _ =>
1510-
typedDependent(args.asInstanceOf[List[untpd.ValDef]])(
1501+
val fixThis = new untpd.UntypedTreeMap:
1502+
// pretype all references of this so that they do not refer to the
1503+
// refined type being constructed
1504+
override def transform(tree: untpd.Tree)(using Context): untpd.Tree = tree match
1505+
case This(id) => untpd.TypedSplice(typedExpr(tree))
1506+
case _ => super.transform(tree)
1507+
1508+
val untpd.Function(fixedArgs: List[untpd.ValDef] @unchecked, fixedResult) =
1509+
fixThis.transform(tree): @unchecked
1510+
typedDependent(fixedArgs, fixedResult)(
15111511
using ctx.fresh.setOwner(newRefinedClassSymbol(tree.span)).setNewScope)
15121512
case _ =>
15131513
if erasedParams.contains(true) then
15141514
typedFunctionType(desugar.makeFunctionWithValDefs(tree, pt), pt)
15151515
else
15161516
val funSym = defn.FunctionSymbol(numArgs, isContextual, isImpure)
1517-
val result = typed(cpy.AppliedTypeTree(tree)(untpd.TypeTree(funSym.typeRef), args :+ body), pt)
1517+
val funTpt = typed(cpy.AppliedTypeTree(tree)(untpd.TypeTree(funSym.typeRef), args :+ result), pt)
15181518
// if there are any erased classes, we need to re-do the typecheck.
1519-
result match
1519+
funTpt match
15201520
case r: AppliedTypeTree if r.args.exists(_.tpe.isErasedClass) =>
15211521
typedFunctionType(desugar.makeFunctionWithValDefs(tree, pt), pt)
1522-
case _ => result
1522+
case _ => funTpt
15231523
}
15241524
}
15251525

tests/neg/i23111.check

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- [E086] Syntax Error: tests/neg/i23111.scala:2:47 --------------------------------------------------------------------
2+
2 | def bar: (a: Int, b: Int) => A.this.type = x => ??? // error
3+
| ^^^^^^^^
4+
| Wrong number of parameters, expected: 2
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E086] Syntax Error: tests/neg/i23111.scala:3:45 --------------------------------------------------------------------
8+
3 | def baz: (a: Int, b: Int) => this.type = x => ??? // error
9+
| ^^^^^^^^
10+
| Wrong number of parameters, expected: 2
11+
|
12+
| longer explanation available when compiling with `-explain`

tests/neg/i23111.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait A:
2+
def bar: (a: Int, b: Int) => A.this.type = x => ??? // error
3+
def baz: (a: Int, b: Int) => this.type = x => ??? // error

0 commit comments

Comments
 (0)