Skip to content

Commit 5688adc

Browse files
committed
Typer refactorings
Pull out calculations of expected types for returns and of types of Super references
1 parent e8bc462 commit 5688adc

File tree

3 files changed

+67
-63
lines changed

3 files changed

+67
-63
lines changed

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,5 +287,50 @@ object SymUtils:
287287
self.addAnnotation(
288288
Annotation(defn.TargetNameAnnot,
289289
Literal(Constant(nameFn(original.targetName).toString)).withSpan(original.span)))
290+
291+
/** The return type as seen from the body of this definition. It is
292+
* computed from the symbol's type by replacing param refs by param symbols.
293+
*/
294+
def localReturnType(using Context): Type =
295+
if self.isConstructor then defn.UnitType
296+
else
297+
def instantiateRT(info: Type, psymss: List[List[Symbol]]): Type = info match
298+
case info: PolyType =>
299+
instantiateRT(info.instantiate(psymss.head.map(_.typeRef)), psymss.tail)
300+
case info: MethodType =>
301+
instantiateRT(info.instantiate(psymss.head.map(_.termRef)), psymss.tail)
302+
case info =>
303+
info.widenExpr
304+
instantiateRT(self.info, self.paramSymss)
305+
306+
/** The expected type of a return to `self` at the place indicated by the context.
307+
* This is the local return type instantiated by the symbols of any context function
308+
* closures that enclose the site of the return
309+
*/
310+
def returnProto(using Context): Type =
311+
312+
/** If `pt` is a context function type, its return type. If the CFT
313+
* is dependent, instantiate with the parameters of the associated
314+
* anonymous function.
315+
* @param paramss the parameters of the anonymous functions
316+
* enclosing the return expression
317+
*/
318+
def instantiateCFT(pt: Type, paramss: => List[List[Symbol]]): Type =
319+
val ift = defn.asContextFunctionType(pt)
320+
if ift.exists then
321+
ift.nonPrivateMember(nme.apply).info match
322+
case appType: MethodType =>
323+
instantiateCFT(appType.instantiate(paramss.head.map(_.termRef)), paramss.tail)
324+
else pt
325+
326+
def iftParamss = ctx.owner.ownersIterator
327+
.filter(_.is(Method, butNot = Accessor))
328+
.takeWhile(_.isAnonymousFunction)
329+
.toList
330+
.reverse
331+
.map(_.paramSymss.head)
332+
333+
instantiateCFT(self.localReturnType, iftParamss)
334+
end returnProto
290335
end extension
291336
end SymUtils

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,19 +235,18 @@ trait TypeAssigner {
235235
else errorType("not a legal qualifying class for this", tree.srcPos))
236236
}
237237

238-
def assignType(tree: untpd.Super, qual: Tree, mixinClass: Symbol = NoSymbol)(using Context): Super = {
239-
val mix = tree.mix
240-
qual.tpe match {
241-
case err: ErrorType => untpd.cpy.Super(tree)(qual, mix).withType(err)
238+
def superType(qualType: Type, mix: untpd.Ident, mixinClass: Symbol, pos: SrcPos)(using Context) =
239+
qualType match
240+
case err: ErrorType => err
242241
case qtype @ ThisType(_) =>
243242
val cls = qtype.cls
244243
def findMixinSuper(site: Type): Type = site.parents filter (_.typeSymbol.name == mix.name) match {
245244
case p :: Nil =>
246245
p.typeConstructor
247246
case Nil =>
248-
errorType(SuperQualMustBeParent(mix, cls), tree.srcPos)
247+
errorType(SuperQualMustBeParent(mix, cls), pos)
249248
case p :: q :: _ =>
250-
errorType("ambiguous parent class qualifier", tree.srcPos)
249+
errorType("ambiguous parent class qualifier", pos)
251250
}
252251
val owntype =
253252
if (mixinClass.exists) mixinClass.appliedRef
@@ -257,9 +256,11 @@ trait TypeAssigner {
257256
val ps = cls.classInfo.parents
258257
if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y)
259258
}
260-
tree.withType(SuperType(cls.thisType, owntype))
261-
}
262-
}
259+
SuperType(cls.thisType, owntype)
260+
261+
def assignType(tree: untpd.Super, qual: Tree, mixinClass: Symbol = NoSymbol)(using Context): Super =
262+
untpd.cpy.Super(tree)(qual, tree.mix)
263+
.withType(superType(qual.tpe, tree.mix, mixinClass, tree.srcPos))
263264

264265
/** Substitute argument type `argType` for parameter `pref` in type `tp`,
265266
* skolemizing the argument type if it is not stable and `pref` occurs in `tp`.

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

Lines changed: 12 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,77 +1669,35 @@ class Typer extends Namer
16691669
caseRest(using ctx.fresh.setFreshGADTBounds.setNewScope)
16701670
}
16711671

1672-
def typedReturn(tree: untpd.Return)(using Context): Return = {
1672+
def typedReturn(tree: untpd.Return)(using Context): Return =
16731673

1674-
/** If `pt` is a context function type, its return type. If the CFT
1675-
* is dependent, instantiate with the parameters of the associated
1676-
* anonymous function.
1677-
* @param paramss the parameters of the anonymous functions
1678-
* enclosing the return expression
1679-
*/
1680-
def instantiateCFT(pt: Type, paramss: => List[List[Symbol]]): Type =
1681-
val ift = defn.asContextFunctionType(pt)
1682-
if ift.exists then
1683-
ift.nonPrivateMember(nme.apply).info match
1684-
case appType: MethodType =>
1685-
instantiateCFT(appType.instantiate(paramss.head.map(_.termRef)), paramss.tail)
1686-
else pt
1687-
1688-
def returnProto(owner: Symbol): Type =
1689-
if (owner.isConstructor) defn.UnitType
1690-
else
1691-
// We need to get the return type of the enclosing function, with all parameters replaced
1692-
// by the local type and value parameters. It would be nice if we could look up that
1693-
// type simply in the tpt field of the enclosing function. But the tree argument in
1694-
// a context is an untyped tree, so we cannot extract its type.
1695-
def instantiateRT(info: Type, psymss: List[List[Symbol]]): Type = info match
1696-
case info: PolyType =>
1697-
instantiateRT(info.instantiate(psymss.head.map(_.typeRef)), psymss.tail)
1698-
case info: MethodType =>
1699-
instantiateRT(info.instantiate(psymss.head.map(_.termRef)), psymss.tail)
1700-
case info =>
1701-
info.widenExpr
1702-
val rt = instantiateRT(owner.info, owner.paramSymss)
1703-
def iftParamss = ctx.owner.ownersIterator
1704-
.filter(_.is(Method, butNot = Accessor))
1705-
.takeWhile(_.isAnonymousFunction)
1706-
.toList
1707-
.reverse
1708-
.map(_.paramSymss.head)
1709-
instantiateCFT(rt, iftParamss)
1710-
1711-
def enclMethInfo(cx: Context): (Tree, Type) = {
1674+
def enclMethInfo(cx: Context): (Tree, Type) =
17121675
val owner = cx.owner
1713-
if (owner.isType) {
1676+
if owner.isType then
17141677
report.error(ReturnOutsideMethodDefinition(owner), tree.srcPos)
17151678
(EmptyTree, WildcardType)
1716-
}
1717-
else if (owner != cx.outer.owner && owner.isRealMethod)
1718-
if (owner.isInlineMethod)
1679+
else if owner != cx.outer.owner && owner.isRealMethod then
1680+
if owner.isInlineMethod then
17191681
(EmptyTree, errorType(NoReturnFromInlineable(owner), tree.srcPos))
1720-
else if (!owner.isCompleted)
1682+
else if !owner.isCompleted then
17211683
(EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.srcPos))
1722-
else {
1723-
val from = Ident(TermRef(NoPrefix, owner.asTerm))
1724-
val proto = returnProto(owner)
1725-
(from, proto)
1726-
}
1684+
else
1685+
(Ident(TermRef(NoPrefix, owner.asTerm)), owner.returnProto)
17271686
else enclMethInfo(cx.outer)
1728-
}
1687+
17291688
val (from, proto) =
1730-
if (tree.from.isEmpty) enclMethInfo(ctx)
1731-
else {
1689+
if tree.from.isEmpty then enclMethInfo(ctx)
1690+
else
17321691
val from = tree.from.asInstanceOf[tpd.Tree]
17331692
val proto =
17341693
if (ctx.erasedTypes) from.symbol.info.finalResultType
17351694
else WildcardType // We cannot reliably detect the internal type view of polymorphic or dependent methods
17361695
// because we do not know the internal type params and method params.
17371696
// Hence no adaptation is possible, and we assume WildcardType as prototype.
17381697
(from, proto)
1739-
}
17401698
val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withSpan(tree.span), proto)
17411699
assignType(cpy.Return(tree)(expr1, from))
1742-
}
1700+
end typedReturn
17431701

17441702
def typedWhileDo(tree: untpd.WhileDo)(using Context): Tree =
17451703
inContext(Nullables.whileContext(tree.span)) {

0 commit comments

Comments
 (0)