Skip to content

Commit 5a7b4b1

Browse files
authored
Fix this references everywhere in dependent function types (#23514)
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 #23111
2 parents 5429b1f + 068d9bb commit 5a7b4b1

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
@@ -1732,11 +1732,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
17321732
else typedFunctionValue(tree, pt)
17331733

17341734
def typedFunctionType(tree: untpd.Function, pt: Type)(using Context): Tree = {
1735-
val untpd.Function(args, body) = tree
1736-
body match
1737-
case untpd.CapturesAndResult(refs, result) =>
1735+
val untpd.Function(args, result) = tree
1736+
result match
1737+
case untpd.CapturesAndResult(refs, result1) =>
17381738
return typedUnadapted(untpd.makeRetaining(
1739-
cpy.Function(tree)(args, result), refs, tpnme.retains), pt)
1739+
cpy.Function(tree)(args, result1), refs, tpnme.retains), pt)
17401740
case _ =>
17411741
var (funFlags, erasedParams) = tree match {
17421742
case tree: untpd.FunctionWithMods => (tree.mods.flags, tree.erasedParams)
@@ -1748,37 +1748,28 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
17481748
val isImpure = funFlags.is(Impure)
17491749

17501750
/** Typechecks dependent function type with given parameters `params` */
1751-
def typedDependent(params: List[untpd.ValDef])(using Context): Tree =
1752-
val fixThis = new untpd.UntypedTreeMap:
1753-
// pretype all references of this in outer context,
1754-
// so that they do not refer to the refined type being constructed
1755-
override def transform(tree: untpd.Tree)(using Context): untpd.Tree = tree match
1756-
case This(id) => untpd.TypedSplice(typedExpr(tree)(using ctx.outer))
1757-
case _ => super.transform(tree)
1758-
1751+
def typedDependent(params: List[untpd.ValDef], result: untpd.Tree)(using Context): Tree =
17591752
val params1 =
17601753
if funFlags.is(Given) then params.map(_.withAddedFlags(Given))
17611754
else params
1762-
val params2 = params1.map(fixThis.transformSub)
1763-
val params3 = params2.zipWithConserve(erasedParams) { (arg, isErased) =>
1755+
val params2 = params1.zipWithConserve(erasedParams): (arg, isErased) =>
17641756
if isErased then arg.withAddedFlags(Erased) else arg
1765-
}
1766-
val appDef0 = untpd.DefDef(nme.apply, List(params3), body, EmptyTree).withSpan(tree.span)
1757+
val appDef0 = untpd.DefDef(nme.apply, List(params2), result, EmptyTree).withSpan(tree.span)
17671758
index(appDef0 :: Nil)
17681759
val appDef = typed(appDef0).asInstanceOf[DefDef]
17691760
val mt = appDef.symbol.info.asInstanceOf[MethodType]
17701761
if (mt.isParamDependent)
17711762
report.error(em"$mt is an illegal function type because it has inter-parameter dependencies", tree.srcPos)
17721763
// Restart typechecking if there are erased classes that we want to mark erased
17731764
if mt.erasedParams.zip(mt.paramInfos.map(_.isErasedClass)).exists((paramErased, classErased) => classErased && !paramErased) then
1774-
val newParams = params3.zipWithConserve(mt.paramInfos.map(_.isErasedClass)) { (arg, isErasedClass) =>
1765+
val newParams = params2.zipWithConserve(mt.paramInfos.map(_.isErasedClass)) { (arg, isErasedClass) =>
17751766
if isErasedClass then arg.withAddedFlags(Erased) else arg
17761767
}
1777-
return typedDependent(newParams)
1768+
return typedDependent(newParams, result)
17781769
val core =
17791770
if mt.hasErasedParams then TypeTree(defn.PolyFunctionClass.typeRef)
17801771
else
1781-
val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(body.span)
1772+
val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(result.span)
17821773
val paramTpts = appDef.termParamss.head.map(p => TypeTree(p.tpt.tpe).withSpan(p.tpt.span))
17831774
val funSym = defn.FunctionSymbol(numArgs, isContextual)
17841775
val tycon = TypeTree(funSym.typeRef)
@@ -1792,19 +1783,28 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
17921783

17931784
args match {
17941785
case ValDef(_, _, _) :: _ =>
1795-
typedDependent(args.asInstanceOf[List[untpd.ValDef]])(
1786+
val fixThis = new untpd.UntypedTreeMap:
1787+
// pretype all references of this so that they do not refer to the
1788+
// refined type being constructed
1789+
override def transform(tree: untpd.Tree)(using Context): untpd.Tree = tree match
1790+
case This(id) => untpd.TypedSplice(typedExpr(tree))
1791+
case _ => super.transform(tree)
1792+
1793+
val untpd.Function(fixedArgs: List[untpd.ValDef] @unchecked, fixedResult) =
1794+
fixThis.transform(tree): @unchecked
1795+
typedDependent(fixedArgs, fixedResult)(
17961796
using ctx.fresh.setOwner(newRefinedClassSymbol(tree.span)).setNewScope)
17971797
case _ =>
17981798
if erasedParams.contains(true) then
17991799
typedFunctionType(desugar.makeFunctionWithValDefs(tree, pt), pt)
18001800
else
18011801
val funSym = defn.FunctionSymbol(numArgs, isContextual, isImpure)
1802-
val result = typed(cpy.AppliedTypeTree(tree)(untpd.TypeTree(funSym.typeRef), args :+ body), pt)
1802+
val funTpt = typed(cpy.AppliedTypeTree(tree)(untpd.TypeTree(funSym.typeRef), args :+ result), pt)
18031803
// if there are any erased classes, we need to re-do the typecheck.
1804-
result match
1804+
funTpt match
18051805
case r: AppliedTypeTree if r.args.exists(_.tpe.isErasedClass) =>
18061806
typedFunctionType(desugar.makeFunctionWithValDefs(tree, pt), pt)
1807-
case _ => result
1807+
case _ => funTpt
18081808
}
18091809
}
18101810

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)