diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index f3bce4000079..e520cc3fd969 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -14,10 +14,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => // Note: the <: Type constraint looks necessary (and is needed to make the file compile in dotc). // But Scalac accepts the program happily without it. Need to find out why. - def unsplice[T >: Untyped](tree: Trees.Tree[T]): Trees.Tree[T] = tree.asInstanceOf[untpd.Tree] match { - case untpd.TypedSplice(tree1) => tree1.asInstanceOf[Trees.Tree[T]] - case _ => tree - } + def unsplice(tree: Trees.Tree[T]): Trees.Tree[T] = tree def isDeclarationOrTypeDef(tree: Tree): Boolean = unsplice(tree) match { case DefDef(_, _, _, _, EmptyTree) @@ -116,7 +113,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case _ => false } - def isSuperSelection(tree: untpd.Tree) = unsplice(tree) match { + def isSuperSelection(tree: Tree) = unsplice(tree) match { case Select(Super(_, _), _) => true case _ => false } @@ -129,7 +126,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => } /** Is tree a variable pattern? */ - def isVarPattern(pat: untpd.Tree): Boolean = unsplice(pat) match { + def isVarPattern(pat: Tree): Boolean = unsplice(pat) match { case x: BackquotedIdent => false case x: Ident => x.name.isVariableName case _ => false @@ -160,7 +157,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => def isLeftAssoc(operator: Name) = !operator.isEmpty && (operator.toSimpleName.last != ':') /** can this type be a type pattern? */ - def mayBeTypePat(tree: untpd.Tree): Boolean = unsplice(tree) match { + def mayBeTypePat(tree: Tree): Boolean = unsplice(tree) match { case AndTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case OrTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind]) @@ -253,6 +250,13 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] import TreeInfo._ import untpd._ + /** The underlying tree when stripping any TypedSplice or Parens nodes */ + override def unsplice(tree: Tree): Tree = tree match { + case TypedSplice(tree1) => tree1 + case Parens(tree1) => unsplice(tree1) + case _ => tree + } + /** True iff definition is a val or def with no right-hand-side, or it * is an abstract typoe declaration */ diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 4999c1dd9ade..d0ab39a988c4 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -104,8 +104,12 @@ object ErrorReporting { def patternConstrStr(tree: Tree): String = ??? - def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = - errorTree(tree, typeMismatchMsg(normalize(tree.tpe, pt), pt, implicitFailure.postscript)) + def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = { + val normTp = normalize(tree.tpe, pt) + val treeTp = if (normTp <:< pt) tree.tpe else normTp + // use normalized type if that also shows an error, original type otherwise + errorTree(tree, typeMismatchMsg(treeTp, pt, implicitFailure.postscript)) + } /** A subtype log explaining why `found` does not conform to `expected` */ def whyNoMatchStr(found: Type, expected: Type) = { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 378cd97cf7cd..80b32260334c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -316,7 +316,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (ctx.mode is Mode.Pattern) { if (name == nme.WILDCARD) return tree.withType(pt) - if (isVarPattern(tree) && name.isTermName) + if (untpd.isVarPattern(tree) && name.isTermName) return typed(desugar.patternVar(tree), pt) } @@ -496,7 +496,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * (x: T) to (x @ (w: T)). This is either `_` or `_*`. */ def cases(ifPat: => Tree, ifExpr: => Tree, wildName: TermName) = tree.expr match { - case id: untpd.Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) => + case id: untpd.Ident if (ctx.mode is Mode.Pattern) && untpd.isVarPattern(id) => if (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) ifPat else { import untpd._ @@ -1114,7 +1114,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedArg(arg: untpd.Tree, tparam: ParamInfo) = { val (desugaredArg, argPt) = if (ctx.mode is Mode.Pattern) - (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramInfo) + (if (untpd.isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramInfo) else (arg, WildcardType) if (tpt1.symbol.isClass) diff --git a/tests/neg/i2514a.scala b/tests/neg/i2514a.scala new file mode 100644 index 000000000000..8a8263666e87 --- /dev/null +++ b/tests/neg/i2514a.scala @@ -0,0 +1,10 @@ +object Foo { + def foo(): Int = { + val f: implicit Int => Int = implicit (x: Int) => 2 * x + f(2) + } + + val f = implicit (x: Int) => x + + (implicit (x: Int) => x): (implicit Int => Int) // error: no implicit argument found +}