@@ -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 is 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,31 +87,33 @@ 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
7998 val tparams = tycon.tpe.typeParams
80- def argNamed (tparam : ParamInfo ) = args.find {
81- case NamedArg (name, _) => name == tparam.paramName
82- case _ => false
83- }.getOrElse(TypeTree (tparam.paramRef))
84- val orderedArgs = if (hasNamedArg(args)) tparams.map(argNamed) else args
8599 val bounds = tparams.map(_.paramInfoAsSeenFrom(tree.tpe).bounds)
86100 def instantiate (bound : Type , args : List [Type ]) =
87101 tparams match
88102 case LambdaParam (lam, _) :: _ =>
89103 HKTypeLambda .fromParams(tparams, bound).appliedTo(args)
90104 case _ =>
91105 bound // paramInfoAsSeenFrom already took care of instantiation in this case
92- if (boundsCheck) checkBounds(orderedArgs, bounds, instantiate, tree.tpe)
106+ if ! ctx.mode.is(Mode .Pattern ) // no bounds checking in patterns
107+ && tycon.symbol != defn.TypeBoxClass // TypeBox types are generated for capture
108+ // conversion, may contain AnyKind as arguments
109+ then
110+ checkBounds(args, bounds, instantiate, tree.tpe, tpt)
93111
94112 def checkWildcardApply (tp : Type ): Unit = tp match {
95113 case tp @ AppliedType (tycon, _) =>
96114 if (tycon.isLambdaSub && tp.hasWildcardArg)
97115 ctx.errorOrMigrationWarning(
98- ex " unreducible application of higher-kinded type $ tycon to wildcard arguments " ,
116+ showInferred( UnreducibleApplication ( tycon), tp, tpt) ,
99117 tree.sourcePos)
100118 case _ =>
101119 }
@@ -104,6 +122,20 @@ object Checking {
104122 checkValidIfApply(ctx.addMode(Mode .AllowLambdaWildcardApply ))
105123 }
106124
125+ /** Check all applied type trees in inferred type `tpt` for well-formedness */
126+ def checkAppliedTypesIn (tpt : TypeTree )(implicit ctx : Context ): Unit =
127+ val checker = new TypeTraverser :
128+ def traverse (tp : Type ) =
129+ tp match
130+ case AppliedType (tycon, argTypes) =>
131+ checkAppliedType(
132+ untpd.AppliedTypeTree (TypeTree (tycon), argTypes.map(TypeTree ))
133+ .withType(tp).withSpan(tpt.span.toSynthetic),
134+ tpt)
135+ case _ =>
136+ traverseChildren(tp)
137+ checker.traverse(tpt.tpe)
138+
107139 def checkNoWildcard (tree : Tree )(implicit ctx : Context ): Tree = tree.tpe match {
108140 case tpe : TypeBounds => errorTree(tree, " no wildcard type allowed here" )
109141 case _ => tree
0 commit comments