@@ -1431,168 +1431,7 @@ class Namer { typer: Typer =>
1431
1431
*/
1432
1432
def valOrDefDefSig (mdef : ValOrDefDef , sym : Symbol , paramss : List [List [Symbol ]], paramFn : Type => Type )(using Context ): Type = {
1433
1433
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 )
1596
1435
lazy val termParamss = paramss.collect { case TermSymbols (vparams) => vparams }
1597
1436
1598
1437
val tptProto = mdef.tpt match {
@@ -1673,15 +1512,184 @@ class Namer { typer: Typer =>
1673
1512
ddef.trailingParamss.foreach(completeParams)
1674
1513
val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor)
1675
1514
sym.setParamss(paramSymss)
1676
- def wrapMethType (restpe : Type ): Type = {
1515
+ def wrapMethType (restpe : Type ): Type =
1677
1516
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
1681
1519
// set result type tree to unit, but take the current class as result type of the symbol
1682
1520
typedAheadType(ddef.tpt, defn.UnitType )
1683
1521
wrapMethType(effectiveResultType(sym, paramSymss))
1684
- }
1685
- else valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
1522
+ else
1523
+ valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
1686
1524
}
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
1687
1695
}
0 commit comments