Skip to content

Add/collection strawman #1160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,10 @@ trait Applications extends Compatibility { self: Typer =>
val alts2 = narrowByShapes(alts1)
//ctx.log(i"narrowed by shape: ${alts1.map(_.symbol.showDcl)}%, %")
if (isDetermined(alts2)) alts2
else narrowByTrees(alts2, pt.typedArgs, resultType)
else {
pretypeArgs(alts2, pt)
narrowByTrees(alts2, pt.typedArgs, resultType)
}
}

case pt @ PolyProto(targs, pt1) =>
Expand Down Expand Up @@ -1122,6 +1125,69 @@ trait Applications extends Compatibility { self: Typer =>
}
}

/** Try to typecheck any arguments in `pt` that are function values missing a
* parameter type. The expected type for these arguments is the lub of the
* corresponding formal parameter types of all alternatives. Type variables
* in formal parameter types are replaced by wildcards. The result of the
* typecheck is stored in `pt`, to be retrieved when its `typedArgs` are selected.
* The benefit of doing this is to allow idioms like this:
*
* def map(f: Char => Char): String = ???
* def map[U](f: Char => U): Seq[U] = ???
* map(x => x.toUpper)
*
* Without `pretypeArgs` we'd get a "missing parameter type" error for `x`.
* With `pretypeArgs`, we use the union of the two formal parameter types
* `Char => Char` and `Char => ?` as the expected type of the closure `x => x.toUpper`.
* That union is `Char => Char`, so we have an expected parameter type `Char`
* for `x`, and the code typechecks.
*/
private def pretypeArgs(alts: List[TermRef], pt: FunProto)(implicit ctx: Context): Unit = {
def recur(altFormals: List[List[Type]], args: List[untpd.Tree]): Unit = args match {
case arg :: args1 if !altFormals.exists(_.isEmpty) =>
def isUnknownParamType(t: untpd.Tree) = t match {
case ValDef(_, tpt, _) => tpt.isEmpty
case _ => false
}
arg match {
case arg: untpd.Function if arg.args.exists(isUnknownParamType) =>
def isUniform[T](xs: List[T])(p: (T, T) => Boolean) = xs.forall(p(_, xs.head))
val formalsForArg: List[Type] = altFormals.map(_.head)
// For alternatives alt_1, ..., alt_n, test whether formal types for current argument are of the form
// (p_1_1, ..., p_m_1) => r_1
// ...
// (p_1_n, ..., p_m_n) => r_n
val decomposedFormalsForArg: List[Option[(List[Type], Type)]] =
formalsForArg.map(defn.FunctionOf.unapply)
if (decomposedFormalsForArg.forall(_.isDefined)) {
val formalParamTypessForArg: List[List[Type]] =
decomposedFormalsForArg.map(_.get._1)
if (isUniform(formalParamTypessForArg)((x, y) => x.length == y.length)) {
val commonParamTypes = formalParamTypessForArg.transpose.map(ps =>
// Given definitions above, for i = 1,...,m,
// ps(i) = List(p_i_1, ..., p_i_n) -- i.e. a column
// If all p_i_k's are the same, assume the type as formal parameter
// type of the i'th parameter of the closure.
if (isUniform(ps)(ctx.typeComparer.isSameTypeWhenFrozen(_, _))) ps.head
else WildcardType)
val commonFormal = defn.FunctionOf(commonParamTypes, WildcardType)
overload.println(i"pretype arg $arg with expected type $commonFormal")
pt.typedArg(arg, commonFormal)
}
}
case _ =>
}
recur(altFormals.map(_.tail), args1)
case _ =>
}
def paramTypes(alt: Type): List[Type] = alt match {
case mt: MethodType => mt.paramTypes
case mt: PolyType => paramTypes(mt.resultType)
case _ => Nil
}
recur(alts.map(alt => paramTypes(alt.widen)), pt.args)
}

private def harmonizeWith[T <: AnyRef](ts: List[T])(tpe: T => Type, adapt: (T, Type) => T)(implicit ctx: Context): List[T] = {
def numericClasses(ts: List[T], acc: Set[Symbol]): Set[Symbol] = ts match {
case t :: ts1 =>
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ object ProtoTypes {
if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
else new FunProto(args, resultType, typer)

def argsAreTyped: Boolean = myTypedArgs.nonEmpty || args.isEmpty
def argsAreTyped: Boolean = myTypedArgs.size == args.length

/** The typed arguments. This takes any arguments already typed using
* `typedArg` into account.
Expand Down
Loading