@@ -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