@@ -42,21 +42,37 @@ import scala.internal.Chars.isOperatorPart
42
42
object Checking {
43
43
import tpd ._
44
44
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
+
45
57
/** A general checkBounds method that can be used for TypeApply nodes as
46
58
* well as for AppliedTypeTree nodes. Also checks that type arguments to
47
59
* *-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.
49
63
*/
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 =
51
66
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))
54
70
}
55
- for (( arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate, app))
71
+ for (arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate, app) do
56
72
ctx.error(
57
- DoesNotConformToBound (arg.tpe, which, bound)(err),
73
+ showInferred(DoesNotConformToBound (arg.tpe, which, bound)(err),
74
+ app, tpt),
58
75
arg.sourcePos.focus)
59
- }
60
76
61
77
/** Check that type arguments `args` conform to corresponding bounds in `tl`
62
78
* Note: This does not check the bounds of AppliedTypeTrees. These
@@ -71,31 +87,33 @@ object Checking {
71
87
* check that it or one of its supertypes can be reduced to a normal application.
72
88
* Unreducible applications correspond to general existentials, and we
73
89
* 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.
74
93
*/
75
- def checkAppliedType (tree : AppliedTypeTree , boundsCheck : Boolean )( implicit ctx : Context ): Unit = {
94
+ def checkAppliedType (tree : AppliedTypeTree , tpt : Tree = EmptyTree )( using ctx : Context ): Unit = {
76
95
val AppliedTypeTree (tycon, args) = tree
77
96
// If `args` is a list of named arguments, return corresponding type parameters,
78
97
// otherwise return type parameters unchanged
79
98
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
85
99
val bounds = tparams.map(_.paramInfoAsSeenFrom(tree.tpe).bounds)
86
100
def instantiate (bound : Type , args : List [Type ]) =
87
101
tparams match
88
102
case LambdaParam (lam, _) :: _ =>
89
103
HKTypeLambda .fromParams(tparams, bound).appliedTo(args)
90
104
case _ =>
91
105
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)
93
111
94
112
def checkWildcardApply (tp : Type ): Unit = tp match {
95
113
case tp @ AppliedType (tycon, _) =>
96
114
if (tycon.isLambdaSub && tp.hasWildcardArg)
97
115
ctx.errorOrMigrationWarning(
98
- ex " unreducible application of higher-kinded type $ tycon to wildcard arguments " ,
116
+ showInferred( UnreducibleApplication ( tycon), tp, tpt) ,
99
117
tree.sourcePos)
100
118
case _ =>
101
119
}
@@ -104,6 +122,20 @@ object Checking {
104
122
checkValidIfApply(ctx.addMode(Mode .AllowLambdaWildcardApply ))
105
123
}
106
124
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
+
107
139
def checkNoWildcard (tree : Tree )(implicit ctx : Context ): Tree = tree.tpe match {
108
140
case tpe : TypeBounds => errorTree(tree, " no wildcard type allowed here" )
109
141
case _ => tree
0 commit comments