@@ -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 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
+
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,8 +87,11 @@ 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
@@ -84,13 +103,14 @@ object Checking {
84
103
HKTypeLambda .fromParams(tparams, bound).appliedTo(args)
85
104
case _ =>
86
105
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)
88
108
89
109
def checkWildcardApply (tp : Type ): Unit = tp match {
90
110
case tp @ AppliedType (tycon, _) =>
91
111
if (tycon.isLambdaSub && tp.hasWildcardArg)
92
112
ctx.errorOrMigrationWarning(
93
- ex " unreducible application of higher-kinded type $ tycon to wildcard arguments " ,
113
+ showInferred( UnreducibleApplication ( tycon), tp, tpt) ,
94
114
tree.sourcePos)
95
115
case _ =>
96
116
}
@@ -99,6 +119,20 @@ object Checking {
99
119
checkValidIfApply(ctx.addMode(Mode .AllowLambdaWildcardApply ))
100
120
}
101
121
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
+
102
136
def checkNoWildcard (tree : Tree )(implicit ctx : Context ): Tree = tree.tpe match {
103
137
case tpe : TypeBounds => errorTree(tree, " no wildcard type allowed here" )
104
138
case _ => tree
0 commit comments