aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala55
-rw-r--r--tests/pos/typers.scala15
3 files changed, 66 insertions, 11 deletions
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index 6eee1f203..cd37c6086 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -222,6 +222,13 @@ object NameOps {
} else name
}
+ /** If this is a default getter, its index (starting from 0), else -1 */
+ def defaultGetterIndex: Int = {
+ val p = name.indexOfSlice(DEFAULT_GETTER)
+ if (p >= 0) name.drop(p + DEFAULT_GETTER.length).toString.toInt - 1
+ else -1
+ }
+
/** The name of a super-accessor */
def superAccessorName: TermName =
SUPER_PREFIX ++ name
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 978c9965d..1e9914ae9 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -420,14 +420,24 @@ class Namer { typer: Typer =>
val pt =
if (!mdef.tpt.isEmpty) WildcardType
else {
+
+ /** Context where `sym` is defined */
+ def defContext(sym: Symbol) =
+ ctx.outersIterator
+ .dropWhile(_.owner != sym)
+ .dropWhile(_.owner == sym)
+ .next
+
+ /** An type for this definition that might be inherited from elsewhere:
+ * If this is a setter parameter, the corresponding getter type.
+ * If this is a class member, the conjunction of all result types
+ * of overridden methods.
+ * NoType if neither case holds.
+ */
val inherited =
- if ((sym is Param) && sym.owner.isSetter) { // fill in type from getter result type
- val getterCtx = ctx.outersIterator
- .dropWhile(_.owner != sym.owner)
- .dropWhile(_.owner == sym.owner)
- .next
- getterCtx.denotNamed(sym.owner.asTerm.name.setterToGetter).info.widenExpr
- }
+ if ((sym is Param) && sym.owner.isSetter) // fill in type from getter result type
+ defContext(sym.owner)
+ .denotNamed(sym.owner.asTerm.name.setterToGetter).info.widenExpr
else if (sym.owner.isTerm) NoType
else {
// TODO: Look only at member of supertype instead?
@@ -442,10 +452,39 @@ class Namer { typer: Typer =>
tp & itpe
}
}
+
+ /** The proto-type to be used when inferring the result type from
+ * the right hand side. This is `WildcardType` except if the definition
+ * is a default getter. In that case, the proto-type is the type of
+ * the corresponding parameter where bound parameters are replaced by
+ * Wildcards.
+ */
+ def rhsProto = {
+ val name = sym.asTerm.name
+ val idx = name.defaultGetterIndex
+ if (idx < 0) WildcardType
+ else {
+ val original = name.defaultGetterToMethod
+ val meth: Denotation =
+ if (original.isConstructorName && (sym.owner is ModuleClass))
+ sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
+ else
+ defContext(sym).denotNamed(original)
+ def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
+ case params :: paramss1 =>
+ if (idx < params.length) (new WildApprox) apply params(idx)
+ else paramProto(paramss1, idx - params.length)
+ case nil =>
+ WildcardType
+ }
+ paramProto(meth.suchThat(_.hasDefaultParams).info.widen.paramTypess, idx)
+ }
+ }
+
// println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
- def rhsType = adapt(typedAheadExpr(mdef.rhs)(rhsCtx), WildcardType).tpe.widen
+ def rhsType = adapt(typedAheadExpr(mdef.rhs)(rhsCtx), rhsProto).tpe.widen
def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
inherited orElse lhsType
}
diff --git a/tests/pos/typers.scala b/tests/pos/typers.scala
index dd08bab07..d7b7989c7 100644
--- a/tests/pos/typers.scala
+++ b/tests/pos/typers.scala
@@ -4,10 +4,19 @@ import annotation.{tailrec, switch}
object typers {
- def fun(x: Int): Int = x + 1
+ object Eta {
+
+ def fun(x: Int): Int = x + 1
+ val foo = fun(_)
+ }
+
+ case class DefaultParams(init: String => String = identity)
+ object DefaultParams {
+ def foo(x: String => String = identity) = x("abc")
+
+ foo()
+ }
- val foo = fun(_)
-
class List[+T] {
def :: (x: T) = new :: (x, this)