Skip to content

Commit b161bd0

Browse files
committed
Better error messages for missing symbols
When I changed branches, the compiler encountered a missing required symbol "DottyPredef.ImplicitConverter" because in the orevious branch that symbol had been renamed to "ImplicitConversion". The error message was not exactly helpful, however: None of the required alternatives of <none> satisfies required predicate This commit fixes this. It gives a meaningful error messages in all cases where a required symbol is missing.
1 parent fcc35d2 commit b161bd0

File tree

3 files changed

+56
-25
lines changed

3 files changed

+56
-25
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,10 +496,10 @@ class Definitions {
496496
def Int_<= : Symbol = Int_leR.symbol
497497
lazy val LongType: TypeRef = valueTypeRef("scala.Long", BoxedLongType, java.lang.Long.TYPE, LongEnc, nme.specializedTypeNames.Long)
498498
def LongClass(implicit ctx: Context): ClassSymbol = LongType.symbol.asClass
499-
lazy val Long_XOR_Long: Symbol = LongType.member(nme.XOR).requiredSymbol(
499+
lazy val Long_XOR_Long: Symbol = LongType.member(nme.XOR).requiredSymbol("method", nme.XOR, LongType.denot)(
500500
x => (x is Method) && (x.info.firstParamTypes.head isRef defn.LongClass)
501501
)
502-
lazy val Long_LSR_Int: Symbol = LongType.member(nme.LSR).requiredSymbol(
502+
lazy val Long_LSR_Int: Symbol = LongType.member(nme.LSR).requiredSymbol("method", nme.LSR, LongType.denot)(
503503
x => (x is Method) && (x.info.firstParamTypes.head isRef defn.IntClass)
504504
)
505505
lazy val Long_plusR: TermRef = LongClass.requiredMethodRef(nme.PLUS, List(LongType))
@@ -729,7 +729,7 @@ class Definitions {
729729
def TupleXXLModule(implicit ctx: Context): Symbol = TupleXXLClass.companionModule
730730

731731
def TupleXXL_apply(implicit ctx: Context): Symbol =
732-
TupleXXLModule.info.member(nme.apply).requiredSymbol(_.info.isVarArgsMethod)
732+
TupleXXLModule.info.member(nme.apply).requiredSymbol("method", nme.apply, TupleXXLModule)(_.info.isVarArgsMethod)
733733

734734
// Annotation base classes
735735
lazy val AnnotationType: TypeRef = ctx.requiredClassRef("scala.annotation.Annotation")

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,14 @@ object Denotations {
276276
* if generateStubs is specified, return a stubsymbol if denotation is a missing ref.
277277
* Throw a `TypeError` if predicate fails to disambiguate symbol or no alternative matches.
278278
*/
279-
def requiredSymbol(p: Symbol => Boolean, source: AbstractFile = null, generateStubs: Boolean = true)(implicit ctx: Context): Symbol =
279+
def requiredSymbol(kind: String,
280+
name: Name,
281+
site: Denotation = NoDenotation,
282+
args: List[Type] = Nil,
283+
source: AbstractFile = null,
284+
generateStubs: Boolean = true)
285+
(p: Symbol => Boolean)
286+
(implicit ctx: Context): Symbol =
280287
disambiguate(p) match {
281288
case m @ MissingRef(ownerd, name) =>
282289
if (generateStubs) {
@@ -285,18 +292,25 @@ object Denotations {
285292
}
286293
else NoSymbol
287294
case NoDenotation | _: NoQualifyingRef =>
288-
throw new TypeError(i"None of the alternatives of $this satisfies required predicate")
295+
def argStr = if (args.isEmpty) "" else i" matching ($args%, %)"
296+
val msg =
297+
if (site.exists) i"$site does not have a member $kind $name$argStr"
298+
else i"missing: $kind $name$argStr"
299+
throw new TypeError(msg)
289300
case denot =>
290301
denot.symbol
291302
}
292303

293-
def requiredMethod(name: PreName)(implicit ctx: Context): TermSymbol =
294-
info.member(name.toTermName).requiredSymbol(_ is Method).asTerm
304+
def requiredMethod(pname: PreName)(implicit ctx: Context): TermSymbol = {
305+
val name = pname.toTermName
306+
info.member(name).requiredSymbol("method", name, this)(_ is Method).asTerm
307+
}
295308
def requiredMethodRef(name: PreName)(implicit ctx: Context): TermRef =
296309
requiredMethod(name).termRef
297310

298-
def requiredMethod(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermSymbol = {
299-
info.member(name.toTermName).requiredSymbol { x =>
311+
def requiredMethod(pname: PreName, argTypes: List[Type])(implicit ctx: Context): TermSymbol = {
312+
val name = pname.toTermName
313+
info.member(name).requiredSymbol(i"method", name, this, argTypes) { x =>
300314
(x is Method) && {
301315
x.info.paramInfoss match {
302316
case paramInfos :: Nil => paramInfos.corresponds(argTypes)(_ =:= _)
@@ -308,16 +322,22 @@ object Denotations {
308322
def requiredMethodRef(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermRef =
309323
requiredMethod(name, argTypes).termRef
310324

311-
def requiredValue(name: PreName)(implicit ctx: Context): TermSymbol =
312-
info.member(name.toTermName).requiredSymbol(_.info.isParameterless).asTerm
325+
def requiredValue(pname: PreName)(implicit ctx: Context): TermSymbol = {
326+
val name = pname.toTermName
327+
info.member(name).requiredSymbol("field or getter", name, this)(_.info.isParameterless).asTerm
328+
}
313329
def requiredValueRef(name: PreName)(implicit ctx: Context): TermRef =
314330
requiredValue(name).termRef
315331

316-
def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
317-
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass
332+
def requiredClass(pname: PreName)(implicit ctx: Context): ClassSymbol = {
333+
val name = pname.toTypeName
334+
info.member(name).requiredSymbol("class", name, this)(_.isClass).asClass
335+
}
318336

319-
def requiredType(name: PreName)(implicit ctx: Context): TypeSymbol =
320-
info.member(name.toTypeName).requiredSymbol(_.isType).asType
337+
def requiredType(pname: PreName)(implicit ctx: Context): TypeSymbol = {
338+
val name = pname.toTypeName
339+
info.member(name).requiredSymbol("type", name, this)(_.isType).asType
340+
}
321341

322342
/** The alternative of this denotation that has a type matching `targetType` when seen
323343
* as a member of type `site`, `NoDenotation` if none exists.

compiler/src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -359,32 +359,43 @@ trait Symbols { this: Context =>
359359

360360
// ----- Locating predefined symbols ----------------------------------------
361361

362-
def requiredPackage(path: PreName): TermSymbol =
363-
base.staticRef(path.toTermName, isPackage = true).requiredSymbol(_ is Package).asTerm
362+
def requiredPackage(path: PreName): TermSymbol = {
363+
val name = path.toTermName
364+
base.staticRef(name, isPackage = true).requiredSymbol("package", name)(_ is Package).asTerm
365+
}
364366

365367
def requiredPackageRef(path: PreName): TermRef = requiredPackage(path).termRef
366368

367-
def requiredClass(path: PreName): ClassSymbol =
368-
base.staticRef(path.toTypeName).requiredSymbol(_.isClass) match {
369+
def requiredClass(path: PreName): ClassSymbol = {
370+
val name = path.toTypeName
371+
base.staticRef(name).requiredSymbol("class", name)(_.isClass) match {
369372
case cls: ClassSymbol => cls
370373
case sym => defn.AnyClass
371374
}
375+
}
372376

373377
def requiredClassRef(path: PreName): TypeRef = requiredClass(path).typeRef
374378

375379
/** Get ClassSymbol if class is either defined in current compilation run
376380
* or present on classpath.
377381
* Returns NoSymbol otherwise. */
378-
def getClassIfDefined(path: PreName): Symbol =
379-
base.staticRef(path.toTypeName, generateStubs = false).requiredSymbol(_.isClass, generateStubs = false)
382+
def getClassIfDefined(path: PreName): Symbol = {
383+
val name = path.toTypeName
384+
base.staticRef(name, generateStubs = false)
385+
.requiredSymbol("class", name, generateStubs = false)(_.isClass)
386+
}
380387

381-
def requiredModule(path: PreName): TermSymbol =
382-
base.staticRef(path.toTermName).requiredSymbol(_ is Module).asTerm
388+
def requiredModule(path: PreName): TermSymbol = {
389+
val name = path.toTermName
390+
base.staticRef(name).requiredSymbol("object", name)(_ is Module).asTerm
391+
}
383392

384393
def requiredModuleRef(path: PreName): TermRef = requiredModule(path).termRef
385394

386-
def requiredMethod(path: PreName): TermSymbol =
387-
base.staticRef(path.toTermName).requiredSymbol(_ is Method).asTerm
395+
def requiredMethod(path: PreName): TermSymbol = {
396+
val name = path.toTermName
397+
base.staticRef(name).requiredSymbol("method", name)(_ is Method).asTerm
398+
}
388399

389400
def requiredMethodRef(path: PreName): TermRef = requiredMethod(path).termRef
390401
}

0 commit comments

Comments
 (0)