Skip to content

Commit 068d9bb

Browse files
committed
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 #23111
1 parent 01447df commit 068d9bb

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)