diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
9 files changed, 74 insertions, 54 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 284b9e21e..de017961a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -683,7 +683,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * * { val xs = es; e' = e' + args } */ - def typedOpAssign: Tree = track("typedOpAssign") { + def typedOpAssign(implicit ctx: Context): Tree = track("typedOpAssign") { val Apply(Select(lhs, name), rhss) = tree val lhs1 = typedExpr(lhs) val liftedDefs = new mutable.ListBuffer[Tree] @@ -805,16 +805,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * whereas overloaded variants need to have a conforming variant. */ def trySelectUnapply(qual: untpd.Tree)(fallBack: Tree => Tree): Tree = { - val genericProto = new UnapplyFunProto(WildcardType, this) - def specificProto = new UnapplyFunProto(selType, this) // try first for non-overloaded, then for overloaded ocurrences def tryWithName(name: TermName)(fallBack: Tree => Tree)(implicit ctx: Context): Tree = - tryEither { - implicit ctx => typedExpr(untpd.Select(qual, name), specificProto) + tryEither { implicit ctx => + val specificProto = new UnapplyFunProto(selType, this) + typedExpr(untpd.Select(qual, name), specificProto) } { (sel, _) => - tryEither { - implicit ctx => typedExpr(untpd.Select(qual, name), genericProto) + tryEither { implicit ctx => + val genericProto = new UnapplyFunProto(WildcardType, this) + typedExpr(untpd.Select(qual, name), genericProto) } { (_, _) => fallBack(sel) } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index fb0497c2b..48f9243f7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -29,6 +29,7 @@ import ErrorReporting.{err, errorType} import config.Printers.typr import collection.mutable import SymDenotations.NoCompleter +import dotty.tools.dotc.reporting.diagnostic.messages.CantInstantiateAbstractClassOrTrait import dotty.tools.dotc.transform.ValueClasses._ object Checking { @@ -103,7 +104,7 @@ object Checking { case tref: TypeRef => val cls = tref.symbol if (cls.is(AbstractOrTrait)) - ctx.error(em"$cls is abstract; cannot be instantiated", pos) + ctx.error(CantInstantiateAbstractClassOrTrait(cls, isTrait = cls.is(Trait)), pos) if (!cls.is(Module)) { // Create a synthetic singleton type instance, and check whether // it conforms to the self type of the class as seen from that instance. diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 1238ad568..9d6a01ab7 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -111,11 +111,23 @@ object ErrorReporting { errorTree(tree, typeMismatchMsg(normalize(tree.tpe, pt), pt, implicitFailure.postscript)) /** A subtype log explaining why `found` does not conform to `expected` */ - def whyNoMatchStr(found: Type, expected: Type) = - if (ctx.settings.explaintypes.value) + def whyNoMatchStr(found: Type, expected: Type) = { + def dropJavaMethod(tp: Type): Type = tp match { + case tp: PolyType => + tp.derivedPolyType(resType = dropJavaMethod(tp.resultType)) + case tp: JavaMethodType => + MethodType(tp.paramNames, tp.paramTypes, dropJavaMethod(tp.resultType)) + case tp => tp + } + val found1 = dropJavaMethod(found) + val expected1 = dropJavaMethod(expected) + if ((found1 eq found) != (expected eq expected1) && (found1 <:< expected1)) + "\n (Note that Scala's and Java's representation of this type differs)" + else if (ctx.settings.explaintypes.value) "\n" + ctx.typerState.show + "\n" + TypeComparer.explained((found <:< expected)(_)) else "" + } def typeMismatchMsg(found: Type, expected: Type, postScript: String = "") = { // replace constrained polyparams and their typevars by their bounds where possible diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6949221fb..48cf0cfac 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -220,7 +220,7 @@ object Implicits { } /** The result of an implicit search */ - abstract class SearchResult extends Showable { + sealed abstract class SearchResult extends Showable { def toText(printer: Printer): Text = printer.toText(this) } diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index f7efb2ac2..3bee0bbe8 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -5,6 +5,7 @@ package typer import ast.{tpd, untpd} import ast.Trees._ import core._ +import printing.{Printer, Showable} import util.SimpleMap import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._ import Decorators.StringInterpolators @@ -13,9 +14,9 @@ object ImportInfo { /** The import info for a root import from given symbol `sym` */ def rootImport(refFn: () => TermRef)(implicit ctx: Context) = { val selectors = untpd.Ident(nme.WILDCARD) :: Nil - def expr = tpd.Ident(refFn()) - def imp = tpd.Import(expr, selectors) - new ImportInfo(imp.symbol, selectors, None, isRootImport = true) + def expr(implicit ctx: Context) = tpd.Ident(refFn()) + def imp(implicit ctx: Context) = tpd.Import(expr, selectors) + new ImportInfo(implicit ctx => imp.symbol, selectors, None, isRootImport = true) } } @@ -27,14 +28,14 @@ object ImportInfo { * @param isRootImport true if this is one of the implicit imports of scala, java.lang, * scala.Predef or dotty.DottyPredef in the start context, false otherwise. */ -class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], - symNameOpt: Option[TermName], val isRootImport: Boolean = false)(implicit ctx: Context) { +class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], + symNameOpt: Option[TermName], val isRootImport: Boolean = false) extends Showable { // Dotty deviation: we cannot use a lazy val here for the same reason // that we cannot use one for `DottyPredefModuleRef`. - def sym = { + def sym(implicit ctx: Context) = { if (mySym == null) { - mySym = symf + mySym = symf(ctx) assert(mySym != null) } mySym @@ -91,7 +92,7 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], } /** The implicit references imported by this import clause */ - def importedImplicits: List[TermRef] = { + def importedImplicits(implicit ctx: Context): List[TermRef] = { val pre = site if (isWildcardImport) { val refs = pre.implicitMembers @@ -115,23 +116,21 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], * override import Predef.{any2stringAdd => _, StringAdd => _, _} // disables String + * override import java.lang.{} // disables all imports */ - lazy val unimported: Symbol = { - lazy val sym = site.termSymbol - def maybeShadowsRoot = symNameOpt match { - case Some(symName) => defn.ShadowableImportNames.contains(symName) - case None => false + def unimported(implicit ctx: Context): Symbol = { + if (myUnimported == null) { + lazy val sym = site.termSymbol + def maybeShadowsRoot = symNameOpt match { + case Some(symName) => defn.ShadowableImportNames.contains(symName) + case None => false + } + myUnimported = + if (maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym)) sym + else NoSymbol + assert(myUnimported != null) } - if (maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym)) sym - else NoSymbol + myUnimported } + private[this] var myUnimported: Symbol = _ - override def toString = { - val siteStr = site.show - val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr - val selectorStr = selectors match { - case Ident(name) :: Nil => name.show - case _ => "{...}" - } - i"import $exprStr.$selectorStr" - } + def toText(printer: Printer) = printer.toText(this) } diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index fde304c69..27c7d0c2f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -27,7 +27,7 @@ import transform.TypeUtils._ object Inliner { import tpd._ - /** Adds accessors accessors for all non-public term members accessed + /** Adds accessors for all non-public term members accessed * from `tree`. Non-public type members are currently left as they are. * This means that references to a private type will lead to typing failures * on the code when it is inlined. Less than ideal, but hard to do better (see below). @@ -190,7 +190,8 @@ object Inliner { val inlineCtx = ctx sym.updateAnnotation(LazyBodyAnnotation { _ => implicit val ctx = inlineCtx - ctx.withNoError(treeExpr(ctx))(makeInlineable) + val body = treeExpr(ctx) + if (ctx.reporter.hasErrors) body else makeInlineable(body) }) } } @@ -233,8 +234,10 @@ object Inliner { * and body that replace it. */ def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = - if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) - new Inliner(tree, bodyToInline(tree.symbol)).inlined(pt) + if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) { + val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors + if (ctx.reporter.hasErrors) tree else new Inliner(tree, body).inlined(pt) + } else errorTree( tree, i"""|Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded, diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 3860ba225..d5f171fe3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -24,6 +24,7 @@ import language.implicitConversions import reporting.diagnostic.messages._ trait NamerContextOps { this: Context => + import NamerContextOps._ /** Enter symbol into current class, if current class is owner of current context, * or into current scope, if not. Should always be called instead of scope.enter @@ -119,22 +120,25 @@ trait NamerContextOps { this: Context => else monotpe } - /** Find moduleClass/sourceModule in effective scope */ - private def findModuleBuddy(name: Name)(implicit ctx: Context) = { - val scope = effectiveScope - val it = scope.lookupAll(name).filter(_ is Module) - assert(it.hasNext, s"no companion $name in $scope") - it.next - } - /** Add moduleClass or sourceModule functionality to completer * for a module or module class */ - def adjustModuleCompleter(completer: LazyType, name: Name) = + def adjustModuleCompleter(completer: LazyType, name: Name) = { + val scope = this.effectiveScope if (name.isTermName) - completer withModuleClass (_ => findModuleBuddy(name.moduleClassName)) + completer withModuleClass (implicit ctx => findModuleBuddy(name.moduleClassName, scope)) else - completer withSourceModule (_ => findModuleBuddy(name.sourceModuleName)) + completer withSourceModule (implicit ctx => findModuleBuddy(name.sourceModuleName, scope)) + } +} + +object NamerContextOps { + /** Find moduleClass/sourceModule in effective scope */ + private def findModuleBuddy(name: Name, scope: Scope)(implicit ctx: Context) = { + val it = scope.lookupAll(name).filter(_ is Module) + assert(it.hasNext, s"no companion $name in $scope") + it.next + } } /** This class creates symbols from definitions and imports and gives them @@ -378,7 +382,7 @@ class Namer { typer: Typer => case ref: RefTree => Some(ref.name.asTermName) case _ => None } - ctx.fresh.setImportInfo(new ImportInfo(sym, imp.selectors, impNameOpt)) + ctx.fresh.setImportInfo(new ImportInfo(implicit ctx => sym, imp.selectors, impNameOpt)) } /** A new context for the interior of a class */ diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index eab91701b..7c573d23c 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -789,7 +789,7 @@ class RefChecks extends MiniPhase { thisTransformer => val sym = tree.symbol if (sym.exists && sym.owner.isTerm && !sym.is(Lazy)) currentLevel.levelAndIndex.get(sym) match { - case Some((level, symIdx)) if symIdx < level.maxIndex => + case Some((level, symIdx)) if symIdx <= level.maxIndex => ctx.error(ForwardReferenceExtendsOverDefinition(sym, level.refSym), level.refPos) case _ => } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 498fd001b..06200d3e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -145,7 +145,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit */ def bindingString(prec: Int, whereFound: Context, qualifier: String = "") = if (prec == wildImport || prec == namedImport) { - ex"""imported$qualifier by ${hl"${whereFound.importInfo.toString}"}""" + ex"""imported$qualifier by ${hl"${whereFound.importInfo}"}""" } else ex"""defined$qualifier in ${hl"${whereFound.owner.toString}"}""" @@ -1964,7 +1964,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (Inliner.hasBodyToInline(tree.symbol) && !ctx.owner.ownersIterator.exists(_.isInlineMethod) && !ctx.settings.YnoInline.value && - !ctx.isAfterTyper) + !ctx.isAfterTyper && + !ctx.reporter.hasErrors) adapt(Inliner.inlineCall(tree, pt), pt) else if (ctx.typeComparer.GADTused && pt.isValueType) // Insert an explicit cast, so that -Ycheck in later phases succeeds. |