@@ -42,21 +42,37 @@ import scala.internal.Chars.isOperatorPart
4242object Checking {
4343 import tpd ._
4444
45+ /** Add further information for error messages involving applied types if the
46+ * type is inferred:
47+ * 1. the full inferred type in a TypeTree node
48+ * 2. the applied type causing the error, if different from (1)
49+ */
50+ private def showInferred (msg : Message , app : Type , tpt : Tree )(using ctx : Context ): Message =
51+ if tpt.isInstanceOf [TypeTree ] then
52+ def subPart = if app eq tpt.tpe then " " else i " subpart $app of "
53+ msg.append(i " in $subPart inferred type ${tpt}" )
54+ .appendExplanation(" \n\n To fix the problem, provide an explicit type." )
55+ else msg
56+
4557 /** A general checkBounds method that can be used for TypeApply nodes as
4658 * well as for AppliedTypeTree nodes. Also checks that type arguments to
4759 * *-type parameters are fully applied.
48- * See TypeOps.boundsViolations for an explanation of the parameters.
60+ * @param tpt If bounds are checked for an AppliedType, the type tree representing
61+ * or (in case it is inferred) containing the type.
62+ * See TypeOps.boundsViolations for an explanation of the first four parameters.
4963 */
50- def checkBounds (args : List [tpd.Tree ], boundss : List [TypeBounds ], instantiate : (Type , List [Type ]) => Type , app : Type = NoType )(implicit ctx : Context ): Unit = {
64+ def checkBounds (args : List [tpd.Tree ], boundss : List [TypeBounds ],
65+ instantiate : (Type , List [Type ]) => Type , app : Type = NoType , tpt : Tree = EmptyTree )(implicit ctx : Context ): Unit =
5166 args.lazyZip(boundss).foreach { (arg, bound) =>
52- if (! bound.isLambdaSub && ! arg.tpe.hasSimpleKind)
53- errorTree(arg, MissingTypeParameterInTypeApp (arg.tpe))
67+ if ! bound.isLambdaSub && ! arg.tpe.hasSimpleKind then
68+ errorTree(arg,
69+ showInferred(MissingTypeParameterInTypeApp (arg.tpe), app, tpt))
5470 }
55- for (( arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate, app))
71+ for (arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate, app) do
5672 ctx.error(
57- DoesNotConformToBound (arg.tpe, which, bound)(err),
73+ showInferred(DoesNotConformToBound (arg.tpe, which, bound)(err),
74+ app, tpt),
5875 arg.sourcePos.focus)
59- }
6076
6177 /** Check that type arguments `args` conform to corresponding bounds in `tl`
6278 * Note: This does not check the bounds of AppliedTypeTrees. These
@@ -71,8 +87,11 @@ object Checking {
7187 * check that it or one of its supertypes can be reduced to a normal application.
7288 * Unreducible applications correspond to general existentials, and we
7389 * cannot handle those.
90+ * @param tree The applied type tree to check
91+ * @param tpt If `tree` is synthesized from a type in a TypeTree,
92+ * the original TypeTree, or EmptyTree otherwise.
7493 */
75- def checkAppliedType (tree : AppliedTypeTree , boundsCheck : Boolean )( implicit ctx : Context ): Unit = {
94+ def checkAppliedType (tree : AppliedTypeTree , tpt : Tree = EmptyTree )( using ctx : Context ): Unit = {
7695 val AppliedTypeTree (tycon, args) = tree
7796 // If `args` is a list of named arguments, return corresponding type parameters,
7897 // otherwise return type parameters unchanged
@@ -84,13 +103,14 @@ object Checking {
84103 HKTypeLambda .fromParams(tparams, bound).appliedTo(args)
85104 case _ =>
86105 bound // paramInfoAsSeenFrom already took care of instantiation in this case
87- if (boundsCheck) checkBounds(args, bounds, instantiate, tree.tpe)
106+ if ! ctx.mode.is(Mode .Pattern ) then
107+ checkBounds(args, bounds, instantiate, tree.tpe, tpt)
88108
89109 def checkWildcardApply (tp : Type ): Unit = tp match {
90110 case tp @ AppliedType (tycon, _) =>
91111 if (tycon.isLambdaSub && tp.hasWildcardArg)
92112 ctx.errorOrMigrationWarning(
93- ex " unreducible application of higher-kinded type $ tycon to wildcard arguments " ,
113+ showInferred( UnreducibleApplication ( tycon), tp, tpt) ,
94114 tree.sourcePos)
95115 case _ =>
96116 }
@@ -99,6 +119,20 @@ object Checking {
99119 checkValidIfApply(ctx.addMode(Mode .AllowLambdaWildcardApply ))
100120 }
101121
122+ /** Check all applied type trees in inferred type `tpt` for well-formedness */
123+ def checkAppliedTypesIn (tpt : TypeTree )(implicit ctx : Context ): Unit =
124+ val checker = new TypeTraverser :
125+ def traverse (tp : Type ) =
126+ tp match
127+ case AppliedType (tycon, argTypes) =>
128+ checkAppliedType(
129+ untpd.AppliedTypeTree (TypeTree (tycon), argTypes.map(TypeTree ))
130+ .withType(tp).withSpan(tpt.span.toSynthetic),
131+ tpt)
132+ case _ =>
133+ traverseChildren(tp)
134+ checker.traverse(tpt.tpe)
135+
102136 def checkNoWildcard (tree : Tree )(implicit ctx : Context ): Tree = tree.tpe match {
103137 case tpe : TypeBounds => errorTree(tree, " no wildcard type allowed here" )
104138 case _ => tree
0 commit comments