Skip to content

Commit 1ee3c51

Browse files
committed
Pull out inferredResultType into separate method
- that way we avoid an overly long valOrDefDefSig # Conflicts: # compiler/src/dotty/tools/dotc/typer/Namer.scala
1 parent 32b8d51 commit 1ee3c51

File tree

1 file changed

+176
-168
lines changed

1 file changed

+176
-168
lines changed

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

Lines changed: 176 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,168 +1431,7 @@ class Namer { typer: Typer =>
14311431
*/
14321432
def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, paramss: List[List[Symbol]], paramFn: Type => Type)(using Context): Type = {
14331433

1434-
def inferredType = {
1435-
/** A type for this definition that might be inherited from elsewhere:
1436-
* If this is a setter parameter, the corresponding getter type.
1437-
* If this is a class member, the conjunction of all result types
1438-
* of overridden methods.
1439-
* NoType if neither case holds.
1440-
*/
1441-
val inherited =
1442-
if (sym.owner.isTerm) NoType
1443-
else
1444-
// TODO: Look only at member of supertype instead?
1445-
lazy val schema = paramFn(WildcardType)
1446-
val site = sym.owner.thisType
1447-
val bcs = sym.owner.info.baseClasses
1448-
if bcs.isEmpty then
1449-
assert(ctx.reporter.errorsReported)
1450-
NoType
1451-
else bcs.tail.foldLeft(NoType: Type) { (tp, cls) =>
1452-
def instantiatedResType(info: Type, paramss: List[List[Symbol]]): Type = info match
1453-
case info: PolyType =>
1454-
paramss match
1455-
case TypeSymbols(tparams) :: paramss1 if info.paramNames.length == tparams.length =>
1456-
instantiatedResType(info.instantiate(tparams.map(_.typeRef)), paramss1)
1457-
case _ =>
1458-
NoType
1459-
case info: MethodType =>
1460-
paramss match
1461-
case TermSymbols(vparams) :: paramss1 if info.paramNames.length == vparams.length =>
1462-
instantiatedResType(info.instantiate(vparams.map(_.termRef)), paramss1)
1463-
case _ =>
1464-
NoType
1465-
case _ =>
1466-
if paramss.isEmpty then info.widenExpr
1467-
else NoType
1468-
1469-
val iRawInfo =
1470-
cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema, sym.targetName).info
1471-
val iResType = instantiatedResType(iRawInfo, paramss).asSeenFrom(site, cls)
1472-
if (iResType.exists)
1473-
typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inherited: $iResType")
1474-
tp & iResType
1475-
}
1476-
end inherited
1477-
1478-
/** If this is a default getter, the type of the corresponding method parameter,
1479-
* otherwise NoType.
1480-
*/
1481-
def defaultParamType = sym.name match
1482-
case DefaultGetterName(original, idx) =>
1483-
val meth: Denotation =
1484-
if (original.isConstructorName && (sym.owner.is(ModuleClass)))
1485-
sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
1486-
else
1487-
ctx.defContext(sym).denotNamed(original)
1488-
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
1489-
case params :: paramss1 =>
1490-
if (idx < params.length) params(idx)
1491-
else paramProto(paramss1, idx - params.length)
1492-
case nil =>
1493-
NoType
1494-
}
1495-
val defaultAlts = meth.altsWith(_.hasDefaultParams)
1496-
if (defaultAlts.length == 1)
1497-
paramProto(defaultAlts.head.info.widen.paramInfoss, idx)
1498-
else
1499-
NoType
1500-
case _ =>
1501-
NoType
1502-
1503-
/** The expected type for a default argument. This is normally the `defaultParamType`
1504-
* with references to internal parameters replaced by wildcards. This replacement
1505-
* makes it possible that the default argument can have a more specific type than the
1506-
* parameter. For instance, we allow
1507-
*
1508-
* class C[A](a: A) { def copy[B](x: B = a): C[B] = C(x) }
1509-
*
1510-
* However, if the default parameter type is a context function type, we
1511-
* have to make sure that wildcard types do not leak into the implicitly
1512-
* generated closure's result type. Test case is pos/i12019.scala. If there
1513-
* would be a leakage with the wildcard approximation, we pick the original
1514-
* default parameter type as expected type.
1515-
*/
1516-
def expectedDefaultArgType =
1517-
val originalTp = defaultParamType
1518-
val approxTp = wildApprox(originalTp)
1519-
approxTp.stripPoly match
1520-
case atp @ defn.ContextFunctionType(_, resType, _)
1521-
if !defn.isNonRefinedFunction(atp) // in this case `resType` is lying, gives us only the non-dependent upper bound
1522-
|| resType.existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false) =>
1523-
originalTp
1524-
case _ =>
1525-
approxTp
1526-
1527-
// println(s"final inherited for $sym: ${inherited.toString}") !!!
1528-
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
1529-
// TODO Scala 3.1: only check for inline vals (no final ones)
1530-
def isInlineVal = sym.isOneOf(FinalOrInline, butNot = Method | Mutable)
1531-
1532-
var rhsCtx = ctx.fresh.addMode(Mode.InferringReturnType)
1533-
if sym.isInlineMethod then rhsCtx = rhsCtx.addMode(Mode.InlineableBody)
1534-
if sym.is(ExtensionMethod) then rhsCtx = rhsCtx.addMode(Mode.InExtensionMethod)
1535-
val typeParams = paramss.collect { case TypeSymbols(tparams) => tparams }.flatten
1536-
if (typeParams.nonEmpty) {
1537-
// we'll be typing an expression from a polymorphic definition's body,
1538-
// so we must allow constraining its type parameters
1539-
// compare with typedDefDef, see tests/pos/gadt-inference.scala
1540-
rhsCtx.setFreshGADTBounds
1541-
rhsCtx.gadt.addToConstraint(typeParams)
1542-
}
1543-
1544-
def typedAheadRhs(pt: Type) =
1545-
PrepareInlineable.dropInlineIfError(sym,
1546-
typedAheadExpr(mdef.rhs, pt)(using rhsCtx))
1547-
1548-
def rhsType =
1549-
// For default getters, we use the corresponding parameter type as an
1550-
// expected type but we run it through `wildApprox` to allow default
1551-
// parameters like in `def mkList[T](value: T = 1): List[T]`.
1552-
val defaultTp = defaultParamType
1553-
val pt = inherited.orElse(expectedDefaultArgType).orElse(WildcardType).widenExpr
1554-
val tp = typedAheadRhs(pt).tpe
1555-
if (defaultTp eq pt) && (tp frozen_<:< defaultTp) then
1556-
// When possible, widen to the default getter parameter type to permit a
1557-
// larger choice of overrides (see `default-getter.scala`).
1558-
// For justification on the use of `@uncheckedVariance`, see
1559-
// `default-getter-variance.scala`.
1560-
AnnotatedType(defaultTp, Annotation(defn.UncheckedVarianceAnnot))
1561-
else
1562-
// don't strip @uncheckedVariance annot for default getters
1563-
TypeOps.simplify(tp.widenTermRefExpr,
1564-
if defaultTp.exists then TypeOps.SimplifyKeepUnchecked() else null) match
1565-
case ctp: ConstantType if isInlineVal => ctp
1566-
case tp => TypeComparer.widenInferred(tp, pt)
1567-
1568-
// Replace aliases to Unit by Unit itself. If we leave the alias in
1569-
// it would be erased to BoxedUnit.
1570-
def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp
1571-
1572-
// Approximate a type `tp` with a type that does not contain skolem types.
1573-
val deskolemize = new ApproximatingTypeMap {
1574-
def apply(tp: Type) = /*trace(i"deskolemize($tp) at $variance", show = true)*/
1575-
tp match {
1576-
case tp: SkolemType => range(defn.NothingType, atVariance(1)(apply(tp.info)))
1577-
case _ => mapOver(tp)
1578-
}
1579-
}
1580-
1581-
def cookedRhsType = deskolemize(dealiasIfUnit(rhsType))
1582-
def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span)
1583-
//if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType")
1584-
if (inherited.exists)
1585-
if (isInlineVal) lhsType else inherited
1586-
else {
1587-
if (sym.is(Implicit))
1588-
mdef match {
1589-
case _: DefDef => missingType(sym, "result ")
1590-
case _: ValDef if sym.owner.isType => missingType(sym, "")
1591-
case _ =>
1592-
}
1593-
lhsType orElse WildcardType
1594-
}
1595-
}
1434+
def inferredType = inferredResultType(mdef, sym, paramss, paramFn, WildcardType)
15961435
lazy val termParamss = paramss.collect { case TermSymbols(vparams) => vparams }
15971436

15981437
val tptProto = mdef.tpt match {
@@ -1673,15 +1512,184 @@ class Namer { typer: Typer =>
16731512
ddef.trailingParamss.foreach(completeParams)
16741513
val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
16751514
sym.setParamss(paramSymss)
1676-
def wrapMethType(restpe: Type): Type = {
1515+
def wrapMethType(restpe: Type): Type =
16771516
instantiateDependent(restpe, paramSymss)
1678-
methodType(paramSymss, restpe, isJava = ddef.mods.is(JavaDefined))
1679-
}
1680-
if (isConstructor) {
1517+
methodType(paramSymss, restpe, ddef.mods.is(JavaDefined))
1518+
if isConstructor then
16811519
// set result type tree to unit, but take the current class as result type of the symbol
16821520
typedAheadType(ddef.tpt, defn.UnitType)
16831521
wrapMethType(effectiveResultType(sym, paramSymss))
1684-
}
1685-
else valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
1522+
else
1523+
valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
16861524
}
1525+
1526+
def inferredResultType(
1527+
mdef: ValOrDefDef,
1528+
sym: Symbol,
1529+
paramss: List[List[Symbol]],
1530+
paramFn: Type => Type,
1531+
fallbackProto: Type
1532+
)(using Context): Type =
1533+
1534+
/** A type for this definition that might be inherited from elsewhere:
1535+
* If this is a setter parameter, the corresponding getter type.
1536+
* If this is a class member, the conjunction of all result types
1537+
* of overridden methods.
1538+
* NoType if neither case holds.
1539+
*/
1540+
val inherited =
1541+
if (sym.owner.isTerm) NoType
1542+
else
1543+
// TODO: Look only at member of supertype instead?
1544+
lazy val schema = paramFn(WildcardType)
1545+
val site = sym.owner.thisType
1546+
val bcs = sym.owner.info.baseClasses
1547+
if bcs.isEmpty then
1548+
assert(ctx.reporter.errorsReported)
1549+
NoType
1550+
else bcs.tail.foldLeft(NoType: Type) { (tp, cls) =>
1551+
def instantiatedResType(info: Type, paramss: List[List[Symbol]]): Type = info match
1552+
case info: PolyType =>
1553+
paramss match
1554+
case TypeSymbols(tparams) :: paramss1 if info.paramNames.length == tparams.length =>
1555+
instantiatedResType(info.instantiate(tparams.map(_.typeRef)), paramss1)
1556+
case _ =>
1557+
NoType
1558+
case info: MethodType =>
1559+
paramss match
1560+
case TermSymbols(vparams) :: paramss1 if info.paramNames.length == vparams.length =>
1561+
instantiatedResType(info.instantiate(vparams.map(_.termRef)), paramss1)
1562+
case _ =>
1563+
NoType
1564+
case _ =>
1565+
if paramss.isEmpty then info.widenExpr
1566+
else NoType
1567+
1568+
val iRawInfo =
1569+
cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema, sym.targetName).info
1570+
val iResType = instantiatedResType(iRawInfo, paramss).asSeenFrom(site, cls)
1571+
if (iResType.exists)
1572+
typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inherited: $iResType")
1573+
tp & iResType
1574+
}
1575+
end inherited
1576+
1577+
/** If this is a default getter, the type of the corresponding method parameter,
1578+
* otherwise NoType.
1579+
*/
1580+
def defaultParamType = sym.name match
1581+
case DefaultGetterName(original, idx) =>
1582+
val meth: Denotation =
1583+
if (original.isConstructorName && (sym.owner.is(ModuleClass)))
1584+
sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
1585+
else
1586+
ctx.defContext(sym).denotNamed(original)
1587+
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
1588+
case params :: paramss1 =>
1589+
if (idx < params.length) params(idx)
1590+
else paramProto(paramss1, idx - params.length)
1591+
case nil =>
1592+
NoType
1593+
}
1594+
val defaultAlts = meth.altsWith(_.hasDefaultParams)
1595+
if (defaultAlts.length == 1)
1596+
paramProto(defaultAlts.head.info.widen.paramInfoss, idx)
1597+
else
1598+
NoType
1599+
case _ =>
1600+
NoType
1601+
1602+
/** The expected type for a default argument. This is normally the `defaultParamType`
1603+
* with references to internal parameters replaced by wildcards. This replacement
1604+
* makes it possible that the default argument can have a more specific type than the
1605+
* parameter. For instance, we allow
1606+
*
1607+
* class C[A](a: A) { def copy[B](x: B = a): C[B] = C(x) }
1608+
*
1609+
* However, if the default parameter type is a context function type, we
1610+
* have to make sure that wildcard types do not leak into the implicitly
1611+
* generated closure's result type. Test case is pos/i12019.scala. If there
1612+
* would be a leakage with the wildcard approximation, we pick the original
1613+
* default parameter type as expected type.
1614+
*/
1615+
def expectedDefaultArgType =
1616+
val originalTp = defaultParamType
1617+
val approxTp = wildApprox(originalTp)
1618+
approxTp.stripPoly match
1619+
case atp @ defn.ContextFunctionType(_, resType, _)
1620+
if !defn.isNonRefinedFunction(atp) // in this case `resType` is lying, gives us only the non-dependent upper bound
1621+
|| resType.existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false) =>
1622+
originalTp
1623+
case _ =>
1624+
approxTp
1625+
1626+
// println(s"final inherited for $sym: ${inherited.toString}") !!!
1627+
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
1628+
// TODO Scala 3.1: only check for inline vals (no final ones)
1629+
def isInlineVal = sym.isOneOf(FinalOrInline, butNot = Method | Mutable)
1630+
1631+
var rhsCtx = ctx.fresh.addMode(Mode.InferringReturnType)
1632+
if sym.isInlineMethod then rhsCtx = rhsCtx.addMode(Mode.InlineableBody)
1633+
if sym.is(ExtensionMethod) then rhsCtx = rhsCtx.addMode(Mode.InExtensionMethod)
1634+
val typeParams = paramss.collect { case TypeSymbols(tparams) => tparams }.flatten
1635+
if (typeParams.nonEmpty) {
1636+
// we'll be typing an expression from a polymorphic definition's body,
1637+
// so we must allow constraining its type parameters
1638+
// compare with typedDefDef, see tests/pos/gadt-inference.scala
1639+
rhsCtx.setFreshGADTBounds
1640+
rhsCtx.gadt.addToConstraint(typeParams)
1641+
}
1642+
1643+
def typedAheadRhs(pt: Type) =
1644+
PrepareInlineable.dropInlineIfError(sym,
1645+
typedAheadExpr(mdef.rhs, pt)(using rhsCtx))
1646+
1647+
def rhsType =
1648+
// For default getters, we use the corresponding parameter type as an
1649+
// expected type but we run it through `wildApprox` to allow default
1650+
// parameters like in `def mkList[T](value: T = 1): List[T]`.
1651+
val defaultTp = defaultParamType
1652+
val pt = inherited.orElse(expectedDefaultArgType).orElse(fallbackProto).widenExpr
1653+
val tp = typedAheadRhs(pt).tpe
1654+
if (defaultTp eq pt) && (tp frozen_<:< defaultTp) then
1655+
// When possible, widen to the default getter parameter type to permit a
1656+
// larger choice of overrides (see `default-getter.scala`).
1657+
// For justification on the use of `@uncheckedVariance`, see
1658+
// `default-getter-variance.scala`.
1659+
AnnotatedType(defaultTp, Annotation(defn.UncheckedVarianceAnnot))
1660+
else
1661+
// don't strip @uncheckedVariance annot for default getters
1662+
TypeOps.simplify(tp.widenTermRefExpr,
1663+
if defaultTp.exists then TypeOps.SimplifyKeepUnchecked() else null) match
1664+
case ctp: ConstantType if isInlineVal => ctp
1665+
case tp => TypeComparer.widenInferred(tp, pt)
1666+
1667+
// Replace aliases to Unit by Unit itself. If we leave the alias in
1668+
// it would be erased to BoxedUnit.
1669+
def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp
1670+
1671+
// Approximate a type `tp` with a type that does not contain skolem types.
1672+
val deskolemize = new ApproximatingTypeMap {
1673+
def apply(tp: Type) = /*trace(i"deskolemize($tp) at $variance", show = true)*/
1674+
tp match {
1675+
case tp: SkolemType => range(defn.NothingType, atVariance(1)(apply(tp.info)))
1676+
case _ => mapOver(tp)
1677+
}
1678+
}
1679+
1680+
def cookedRhsType = deskolemize(dealiasIfUnit(rhsType))
1681+
def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span)
1682+
//if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType")
1683+
if (inherited.exists)
1684+
if (isInlineVal) lhsType else inherited
1685+
else {
1686+
if (sym.is(Implicit))
1687+
mdef match {
1688+
case _: DefDef => missingType(sym, "result ")
1689+
case _: ValDef if sym.owner.isType => missingType(sym, "")
1690+
case _ =>
1691+
}
1692+
lhsType orElse WildcardType
1693+
}
1694+
end inferredResultType
16871695
}

0 commit comments

Comments
 (0)