@@ -67,6 +67,7 @@ object Inliner {
67
67
*/
68
68
def inlineCall (tree : Tree )(implicit ctx : Context ): Tree = {
69
69
if (tree.symbol == defn.CompiletimeTesting_typeChecks ) return Intrinsics .typeChecks(tree)
70
+ if (tree.symbol == defn.CompiletimeTesting_typeCheckErrors ) return Intrinsics .typeCheckErrors(tree)
70
71
71
72
/** Set the position of all trees logically contained in the expansion of
72
73
* inlined call `call` to the position of `call`. This transform is necessary
@@ -193,10 +194,12 @@ object Inliner {
193
194
}
194
195
195
196
object Intrinsics {
197
+ import dotty .tools .dotc .reporting .diagnostic .messages .Error
198
+ private enum ErrorKind
199
+ case Parser , Typer
196
200
197
- /** Expand call to scala.compiletime.testing.typeChecks */
198
- def typeChecks (tree : Tree )(implicit ctx : Context ): Tree = {
199
- assert(tree.symbol == defn.CompiletimeTesting_typeChecks )
201
+ private def compileForErrors (tree : Tree , stopAfterParser : Boolean )(given ctx : Context ): List [(ErrorKind , Error )] =
202
+ assert(tree.symbol == defn.CompiletimeTesting_typeChecks || tree.symbol == defn.CompiletimeTesting_typeCheckErrors )
200
203
def stripTyped (t : Tree ): Tree = t match {
201
204
case Typed (t2, _) => stripTyped(t2)
202
205
case _ => t
@@ -205,20 +208,49 @@ object Inliner {
205
208
val Apply (_, codeArg :: Nil ) = tree
206
209
ConstFold (stripTyped(codeArg.underlyingArgument)).tpe.widenTermRefExpr match {
207
210
case ConstantType (Constant (code : String )) =>
208
- val ctx2 = ctx.fresh.setNewTyperState().setTyper(new Typer )
209
- val tree2 = new Parser (SourceFile .virtual(" tasty-reflect" , code))(ctx2).block()
210
- val res =
211
- if (ctx2.reporter.hasErrors) false
212
- else {
213
- ctx2.typer.typed(tree2)(ctx2)
214
- ! ctx2.reporter.hasErrors
215
- }
216
- Literal (Constant (res))
211
+ val source2 = SourceFile .virtual(" tasty-reflect" , code)
212
+ val ctx2 = ctx.fresh.setNewTyperState().setTyper(new Typer ).setSource(source2)
213
+ val tree2 = new Parser (source2)(ctx2).block()
214
+ val res = collection.mutable.ListBuffer .empty[(ErrorKind , Error )]
215
+
216
+ val parseErrors = ctx2.reporter.allErrors.toList
217
+ res ++= parseErrors.map(e => ErrorKind .Parser -> e)
218
+ if ! stopAfterParser || res.isEmpty
219
+ ctx2.typer.typed(tree2)(ctx2)
220
+ val typerErrors = ctx2.reporter.allErrors.filterNot(parseErrors.contains)
221
+ res ++= typerErrors.map(e => ErrorKind .Typer -> e)
222
+ res.toList
217
223
case t =>
218
224
assert(ctx.reporter.hasErrors) // at least: argument to inline parameter must be a known value
219
- EmptyTree
225
+ Nil
220
226
}
221
- }
227
+
228
+ private def packError (kind : ErrorKind , error : Error )(given Context ): Tree =
229
+ def lit (x : Any ) = Literal (Constant (x))
230
+ val constructor : Tree = ref(defn.CompiletimeTesting_Error_apply )
231
+ val parserErrorKind : Tree = ref(defn.CompiletimeTesting_ErrorKind_Parser )
232
+ val typerErrorKind : Tree = ref(defn.CompiletimeTesting_ErrorKind_Typer )
233
+
234
+ constructor.appliedTo(
235
+ lit(error.message), lit(error.pos.lineContent), lit(error.pos.column),
236
+ if kind == ErrorKind .Parser then parserErrorKind else typerErrorKind)
237
+
238
+ private def packErrors (errors : List [(ErrorKind , Error )])(given Context ): Tree =
239
+ val individualErrors : List [Tree ] = errors.map(packError)
240
+ val errorTpt = ref(defn.CompiletimeTesting_ErrorClass )
241
+ ref(defn.ListModule ).select(nme.apply)
242
+ .appliedToTypeTree(errorTpt)
243
+ .appliedToVarargs(individualErrors, errorTpt)
244
+
245
+ /** Expand call to scala.compiletime.testing.typeChecks */
246
+ def typeChecks (tree : Tree )(given Context ): Tree =
247
+ val errors = compileForErrors(tree, true )
248
+ Literal (Constant (errors.isEmpty))
249
+
250
+ /** Expand call to scala.compiletime.testing.typeCheckErrors */
251
+ def typeCheckErrors (tree : Tree )(given Context ): Tree =
252
+ val errors = compileForErrors(tree, false )
253
+ packErrors(errors)
222
254
}
223
255
}
224
256
0 commit comments