diff options
author | Martin Odersky <odersky@gmail.com> | 2016-07-16 15:21:12 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-07-16 15:21:21 +0200 |
commit | 0eb2d76c467a53786ae6147c9c983c23ab0894c8 (patch) | |
tree | 44db7e49882c87f2906d6d21dca564c0d5407d38 | |
parent | bd45ecc06b04c3788d1ce706508eed5e0c50b50b (diff) | |
download | dotty-0eb2d76c467a53786ae6147c9c983c23ab0894c8.tar.gz dotty-0eb2d76c467a53786ae6147c9c983c23ab0894c8.tar.bz2 dotty-0eb2d76c467a53786ae6147c9c983c23ab0894c8.zip |
Proparage function result constrains when inferring parameter types
If an application has functions with implicit parameter types we need to be
more aggressive about propagating knowledge of the expected result type into
the constraint.
Fixes #1378.
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 7 | ||||
-rw-r--r-- | tests/pos/i1378.scala | 3 |
5 files changed, 33 insertions, 2 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index c1efd0b0b..55eb21687 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -278,7 +278,18 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => } trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] => - // todo: fill with methods from TreeInfo that only apply to untpd.Tree's + import TreeInfo._ + + def isFunctionWithImplicitParamType(tree: Tree) = tree match { + case untpd.Function(args, _) => + args.exists { + case ValDef(_, tpt, _) => tpt.isEmpty + case _ => false + } + case _ => false + } + + // todo: fill with other methods from TreeInfo that only apply to untpd.Tree's } trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 6e78a570d..7a742112b 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -553,6 +553,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // a modified tree but this would be more convoluted and less efficient. if (proto.isTupled) proto = proto.tupled + // If some of the application's arguments are function literals without explicitly declared + // parameter types, and the expected type is a value type, relate the + // normalized result type of the application with the expected type through `<:<`. + // This can add more constraints which help sharpen the inferred parameter + // types for the argument function literal(s). + // This tweak is needed to make i1348 compile. + if (tree.args.exists(untpd.isFunctionWithImplicitParamType(_))) + if (!constrainResult(fun1.tpe.widen, proto.derivedFunProto(resultType = pt))) + typr.println(i"result failure for $tree with type ${fun1.tpe.widen}, expected = $pt") + fun1.tpe match { case ErrorType => tree.withType(ErrorType) case TryDynamicCallType => diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index a430d5f75..767ccbe7d 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -175,7 +175,7 @@ object ProtoTypes { def isMatchedBy(tp: Type)(implicit ctx: Context) = typer.isApplicable(tp, Nil, typedArgs, resultType) - def derivedFunProto(args: List[untpd.Tree], resultType: Type, typer: Typer) = + def derivedFunProto(args: List[untpd.Tree] = this.args, resultType: Type, typer: Typer = this.typer) = if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this else new FunProto(args, resultType, typer) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 11a7b6753..13b6167b1 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -597,6 +597,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt) else { val params = args.asInstanceOf[List[untpd.ValDef]] + + pt match { + case pt: TypeVar if untpd.isFunctionWithImplicitParamType(tree) => + isFullyDefined(pt, ForceDegree.noBottom) + case _ => + } + val (protoFormals, protoResult) = decomposeProtoFunction(pt, params.length) def refersTo(arg: untpd.Tree, param: untpd.ValDef): Boolean = arg match { diff --git a/tests/pos/i1378.scala b/tests/pos/i1378.scala new file mode 100644 index 000000000..31475daf2 --- /dev/null +++ b/tests/pos/i1378.scala @@ -0,0 +1,3 @@ +object Test { + (1, x => 2): (Int, Int => Int) +} |