From 9b32b8a4444ae1434472869552f84c931099ad1b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 23 Mar 2018 14:25:00 +0100 Subject: [PATCH 1/2] Avoid "missing parameter type" error when checking `isMatchedBy` When checking whether a FunProto is applicable to an argument, we should avoid falling into "missing parameter type" errors. Better to assume a WildcardType for the argument instead. This follows the general principle to err on the side of generosity when checking `isMatchedBy`. --- .../dotty/tools/dotc/typer/ProtoTypes.scala | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 85a828b9a401..96829e727883 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -212,7 +212,7 @@ object ProtoTypes { private[this] var evalState: SimpleIdentityMap[untpd.Tree, (TyperState, Constraint)] = SimpleIdentityMap.Empty def isMatchedBy(tp: Type)(implicit ctx: Context) = - typer.isApplicable(tp, Nil, typedArgs, resultType) + typer.isApplicable(tp, Nil, unforcedTypedArgs, resultType) 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 @@ -240,13 +240,19 @@ object ProtoTypes { myTypedArg.size == args.length } - private def cacheTypedArg(arg: untpd.Tree, typerFn: untpd.Tree => Tree)(implicit ctx: Context): Tree = { + private def cacheTypedArg(arg: untpd.Tree, typerFn: untpd.Tree => Tree, force: Boolean)(implicit ctx: Context): Tree = { var targ = myTypedArg(arg) if (targ == null) { - targ = typerFn(arg) - if (!ctx.reporter.hasPending) { - myTypedArg = myTypedArg.updated(arg, targ) - evalState = evalState.updated(arg, (ctx.typerState, ctx.typerState.constraint)) + if (!force && untpd.functionWithUnknownParamType(arg).isDefined) + // If force = true, assume ? rather than reporting an error. + // That way we don't cause a "missing parameter" error in `typerFn(arg)` + targ = arg.withType(WildcardType) + else { + targ = typerFn(arg) + if (!ctx.reporter.hasPending) { + myTypedArg = myTypedArg.updated(arg, targ) + evalState = evalState.updated(arg, (ctx.typerState, ctx.typerState.constraint)) + } } } targ @@ -254,19 +260,25 @@ object ProtoTypes { /** The typed arguments. This takes any arguments already typed using * `typedArg` into account. + * @param force if true try to typecheck arguments even if they are functions + * with unknown parameter types - this will then cause a + * "missing parameter type" error */ - def typedArgs: List[Tree] = { + private def typedArgs(force: Boolean): List[Tree] = { if (myTypedArgs.size != args.length) - myTypedArgs = args.mapconserve(cacheTypedArg(_, typer.typed(_))) + myTypedArgs = args.mapconserve(cacheTypedArg(_, typer.typed(_), force)) myTypedArgs } + def typedArgs: List[Tree] = typedArgs(force = true) + def unforcedTypedArgs: List[Tree] = typedArgs(force = false) + /** Type single argument and remember the unadapted result in `myTypedArg`. * used to avoid repeated typings of trees when backtracking. */ def typedArg(arg: untpd.Tree, formal: Type)(implicit ctx: Context): Tree = { val locked = ctx.typerState.ownedVars - val targ = cacheTypedArg(arg, typer.typedUnadapted(_, formal, locked)) + val targ = cacheTypedArg(arg, typer.typedUnadapted(_, formal, locked), force = true) typer.adapt(targ, formal, locked) } From 388933304f155a0dbf677f3d7634aea3c6581866 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 23 Mar 2018 16:52:51 +0100 Subject: [PATCH 2/2] Fix typo --- compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 96829e727883..5aa4a2fbfd31 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -244,7 +244,7 @@ object ProtoTypes { var targ = myTypedArg(arg) if (targ == null) { if (!force && untpd.functionWithUnknownParamType(arg).isDefined) - // If force = true, assume ? rather than reporting an error. + // If force = false, assume ? rather than reporting an error. // That way we don't cause a "missing parameter" error in `typerFn(arg)` targ = arg.withType(WildcardType) else { @@ -261,7 +261,7 @@ object ProtoTypes { /** The typed arguments. This takes any arguments already typed using * `typedArg` into account. * @param force if true try to typecheck arguments even if they are functions - * with unknown parameter types - this will then cause a + * with unknown parameter types - this will then cause a * "missing parameter type" error */ private def typedArgs(force: Boolean): List[Tree] = {