Skip to content

Better error messages for missing symbols #5627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -496,10 +496,10 @@ class Definitions {
def Int_<= : Symbol = Int_leR.symbol
lazy val LongType: TypeRef = valueTypeRef("scala.Long", BoxedLongType, java.lang.Long.TYPE, LongEnc, nme.specializedTypeNames.Long)
def LongClass(implicit ctx: Context): ClassSymbol = LongType.symbol.asClass
lazy val Long_XOR_Long: Symbol = LongType.member(nme.XOR).requiredSymbol(
lazy val Long_XOR_Long: Symbol = LongType.member(nme.XOR).requiredSymbol("method", nme.XOR, LongType.denot)(
x => (x is Method) && (x.info.firstParamTypes.head isRef defn.LongClass)
)
lazy val Long_LSR_Int: Symbol = LongType.member(nme.LSR).requiredSymbol(
lazy val Long_LSR_Int: Symbol = LongType.member(nme.LSR).requiredSymbol("method", nme.LSR, LongType.denot)(
x => (x is Method) && (x.info.firstParamTypes.head isRef defn.IntClass)
)
lazy val Long_plusR: TermRef = LongClass.requiredMethodRef(nme.PLUS, List(LongType))
Expand Down Expand Up @@ -729,7 +729,7 @@ class Definitions {
def TupleXXLModule(implicit ctx: Context): Symbol = TupleXXLClass.companionModule

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

// Annotation base classes
lazy val AnnotationType: TypeRef = ctx.requiredClassRef("scala.annotation.Annotation")
Expand Down
44 changes: 32 additions & 12 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,14 @@ object Denotations {
* if generateStubs is specified, return a stubsymbol if denotation is a missing ref.
* Throw a `TypeError` if predicate fails to disambiguate symbol or no alternative matches.
*/
def requiredSymbol(p: Symbol => Boolean, source: AbstractFile = null, generateStubs: Boolean = true)(implicit ctx: Context): Symbol =
def requiredSymbol(kind: String,
name: Name,
site: Denotation = NoDenotation,
args: List[Type] = Nil,
source: AbstractFile = null,
generateStubs: Boolean = true)
(p: Symbol => Boolean)
(implicit ctx: Context): Symbol =
disambiguate(p) match {
case m @ MissingRef(ownerd, name) =>
if (generateStubs) {
Expand All @@ -285,18 +292,25 @@ object Denotations {
}
else NoSymbol
case NoDenotation | _: NoQualifyingRef =>
throw new TypeError(i"None of the alternatives of $this satisfies required predicate")
def argStr = if (args.isEmpty) "" else i" matching ($args%, %)"
val msg =
if (site.exists) i"$site does not have a member $kind $name$argStr"
else i"missing: $kind $name$argStr"
throw new TypeError(msg)
case denot =>
denot.symbol
}

def requiredMethod(name: PreName)(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(_ is Method).asTerm
def requiredMethod(pname: PreName)(implicit ctx: Context): TermSymbol = {
val name = pname.toTermName
info.member(name).requiredSymbol("method", name, this)(_ is Method).asTerm
}
def requiredMethodRef(name: PreName)(implicit ctx: Context): TermRef =
requiredMethod(name).termRef

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

def requiredValue(name: PreName)(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(_.info.isParameterless).asTerm
def requiredValue(pname: PreName)(implicit ctx: Context): TermSymbol = {
val name = pname.toTermName
info.member(name).requiredSymbol("field or getter", name, this)(_.info.isParameterless).asTerm
}
def requiredValueRef(name: PreName)(implicit ctx: Context): TermRef =
requiredValue(name).termRef

def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass
def requiredClass(pname: PreName)(implicit ctx: Context): ClassSymbol = {
val name = pname.toTypeName
info.member(name).requiredSymbol("class", name, this)(_.isClass).asClass
}

def requiredType(name: PreName)(implicit ctx: Context): TypeSymbol =
info.member(name.toTypeName).requiredSymbol(_.isType).asType
def requiredType(pname: PreName)(implicit ctx: Context): TypeSymbol = {
val name = pname.toTypeName
info.member(name).requiredSymbol("type", name, this)(_.isType).asType
}

/** The alternative of this denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
Expand Down
31 changes: 21 additions & 10 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -359,32 +359,43 @@ trait Symbols { this: Context =>

// ----- Locating predefined symbols ----------------------------------------

def requiredPackage(path: PreName): TermSymbol =
base.staticRef(path.toTermName, isPackage = true).requiredSymbol(_ is Package).asTerm
def requiredPackage(path: PreName): TermSymbol = {
val name = path.toTermName
base.staticRef(name, isPackage = true).requiredSymbol("package", name)(_ is Package).asTerm
}

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

def requiredClass(path: PreName): ClassSymbol =
base.staticRef(path.toTypeName).requiredSymbol(_.isClass) match {
def requiredClass(path: PreName): ClassSymbol = {
val name = path.toTypeName
base.staticRef(name).requiredSymbol("class", name)(_.isClass) match {
case cls: ClassSymbol => cls
case sym => defn.AnyClass
}
}

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

/** Get ClassSymbol if class is either defined in current compilation run
* or present on classpath.
* Returns NoSymbol otherwise. */
def getClassIfDefined(path: PreName): Symbol =
base.staticRef(path.toTypeName, generateStubs = false).requiredSymbol(_.isClass, generateStubs = false)
def getClassIfDefined(path: PreName): Symbol = {
val name = path.toTypeName
base.staticRef(name, generateStubs = false)
.requiredSymbol("class", name, generateStubs = false)(_.isClass)
}

def requiredModule(path: PreName): TermSymbol =
base.staticRef(path.toTermName).requiredSymbol(_ is Module).asTerm
def requiredModule(path: PreName): TermSymbol = {
val name = path.toTermName
base.staticRef(name).requiredSymbol("object", name)(_ is Module).asTerm
}

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

def requiredMethod(path: PreName): TermSymbol =
base.staticRef(path.toTermName).requiredSymbol(_ is Method).asTerm
def requiredMethod(path: PreName): TermSymbol = {
val name = path.toTermName
base.staticRef(name).requiredSymbol("method", name)(_ is Method).asTerm
}

def requiredMethodRef(path: PreName): TermRef = requiredMethod(path).termRef
}
Expand Down