diff options
17 files changed, 227 insertions, 85 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 2801bcae2..c4b2b2122 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -32,7 +32,7 @@ object Trees { /** Property key for trees with documentation strings attached */ val DocComment = new Property.Key[Comment] - @sharable private var nextId = 0 // for debugging + @sharable private var nextId = 0 // for debugging type LazyTree = AnyRef /* really: Tree | Lazy[Tree] */ type LazyTreeList = AnyRef /* really: List[Tree] | Lazy[List[Tree]] */ diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 639c4d111..a1b99d16d 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -216,8 +216,8 @@ object Contexts { else if (isNonEmptyScopeContext) scope.implicitDecls else Nil val outerImplicits = - if (isImportContext && importInfo.hiddenRoot.exists) - outer.implicits exclude importInfo.hiddenRoot + if (isImportContext && importInfo.unimported.exists) + outer.implicits exclude importInfo.unimported else outer.implicits if (implicitRefs.isEmpty) outerImplicits @@ -422,9 +422,18 @@ object Contexts { final def withOwner(owner: Symbol): Context = if (owner ne this.owner) fresh.setOwner(owner) else this - override def toString = + final def withProperty[T](key: Key[T], value: Option[T]): Context = + if (property(key) == value) this + else value match { + case Some(v) => fresh.setProperty(key, v) + case None => fresh.dropProperty(key) + } + + override def toString = { + def iinfo(implicit ctx: Context) = if (ctx.importInfo == null) "" else i"${ctx.importInfo.selectors}%, %" "Context(\n" + - (outersIterator map ( ctx => s" owner = ${ctx.owner}, scope = ${ctx.scope}") mkString "\n") + (outersIterator map ( ctx => s" owner = ${ctx.owner}, scope = ${ctx.scope}, import = ${iinfo(ctx)}") mkString "\n") + } } /** A condensed context provides only a small memory footprint over @@ -468,6 +477,9 @@ object Contexts { def setProperty[T](key: Key[T], value: T): this.type = setMoreProperties(moreProperties.updated(key, value)) + def dropProperty(key: Key[_]): this.type = + setMoreProperties(moreProperties - key) + def setPhase(pid: PhaseId): this.type = setPeriod(Period(runId, pid)) def setPhase(phase: Phase): this.type = setPeriod(Period(runId, phase.start, phase.end)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 4b090d9b1..c5ccab261 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -650,6 +650,13 @@ class Definitions { def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple) def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product) + val predefClassNames: Set[Name] = + Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName) + + /** Is `cls` the predef module class, or a class inherited by Predef? */ + def isPredefClass(cls: Symbol) = + (cls.owner eq ScalaPackageClass) && predefClassNames.contains(cls.name) + val StaticRootImportFns = List[() => TermRef]( () => JavaLangPackageVal.termRef, () => ScalaPackageVal.termRef diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index 222e2235d..6a53e1b30 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -26,7 +26,10 @@ trait Phases { def phasesStack: List[Phase] = if ((this eq NoContext) || !phase.exists) Nil - else phase :: outersIterator.dropWhile(_.phase == phase).next.phasesStack + else { + val rest = outersIterator.dropWhile(_.phase == phase) + phase :: (if (rest.hasNext) rest.next.phasesStack else Nil) + } /** Execute `op` at given phase */ def atPhase[T](phase: Phase)(op: Context => T): T = diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 00627fc28..1ddf3cd6d 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -614,14 +614,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { (sym.allOverriddenSymbols exists (_ is TypeParam)) override def toText(sym: Symbol): Text = { - if (sym.isImport) { - def importString(tree: untpd.Tree) = s"import ${tree.show}" + if (sym.isImport) sym.infoOrCompleter match { - case info: Namer#Completer => return importString(info.original) - case info: ImportType => return importString(info.expr) + case info: Namer#Completer => return info.original.show + case info: ImportType => return s"import $info.expr.show" case _ => } - } if (sym.is(ModuleClass)) kindString(sym) ~~ (nameString(sym.name.stripModuleClassSuffix) + idString(sym)) else diff --git a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala index f269fef64..d849ea370 100644 --- a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala +++ b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala @@ -6,7 +6,7 @@ import java.io.{ File, PrintWriter, PrintStream, StringWriter, Writer, OutputStream, ByteArrayOutputStream => ByteOutputStream } -import java.lang.{Class, ClassLoader} +import java.lang.{Class, ClassLoader, Thread, System, StringBuffer} import java.net.{URL, URLClassLoader} import scala.collection.immutable.ListSet diff --git a/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala b/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala index b3ac41c55..cfe8d892d 100644 --- a/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala +++ b/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala @@ -4,7 +4,7 @@ package repl import java.io.{BufferedReader, File, FileReader, PrintWriter} import java.io.IOException -import java.lang.{ClassLoader, System} +import java.lang.{ClassLoader, System, Thread} import scala.concurrent.{Future, Await} import scala.concurrent.duration.Duration import reporting.Reporter diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala index 714255962..331fce46a 100644 --- a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala @@ -9,7 +9,6 @@ import dotty.tools.dotc.core.Symbols.NoSymbol import scala.annotation.tailrec import dotty.tools.dotc.core._ import Symbols._ -import scala.Some import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer} import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.core.Contexts.Context diff --git a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala index c444631ae..cd374e32c 100644 --- a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -44,6 +44,12 @@ class FrontEnd extends Phase { typr.println("entered: " + unit.source) } + def enterAnnotations(implicit ctx: Context) = monitor("annotating") { + val unit = ctx.compilationUnit + ctx.typer.annotate(unit.untpdTree :: Nil) + typr.println("annotated: " + unit.source) + } + def typeCheck(implicit ctx: Context) = monitor("typechecking") { val unit = ctx.compilationUnit unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree) @@ -69,8 +75,9 @@ class FrontEnd extends Phase { } unitContexts foreach (parse(_)) record("parsedTrees", ast.Trees.ntrees) - unitContexts foreach (enterSyms(_)) - unitContexts foreach (typeCheck(_)) + unitContexts.foreach(enterSyms(_)) + unitContexts.foreach(enterAnnotations(_)) + unitContexts.foreach(typeCheck(_)) record("total trees after typer", ast.Trees.ntrees) unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper) } diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 3aa289181..b4ec3390e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -95,14 +95,22 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], val isRootImp /** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden. * Note: this computation needs to work even for un-initialized import infos, and * is not allowed to force initialization. + * + * TODO: Once we have fully bootstrapped, I would prefer if we expressed + * unimport with an `override` modifier, and generalized it to all imports. + * I believe this would be more transparent than the curren set of conditions. E.g. + * + * override import Predef.{any2stringAdd => _, StringAdd => _, _} // disables String + + * override import java.lang.{} // disables all imports */ - lazy val hiddenRoot: Symbol = { - val sym = site.termSymbol - def hasMaskingSelector = selectors exists { + lazy val unimported: Symbol = { + lazy val sym = site.termSymbol + val hasMaskingSelector = selectors exists { case Thicket(_ :: Ident(nme.WILDCARD) :: Nil) => true case _ => false } - if ((defn.RootImportTypes exists (_.symbol == sym)) && hasMaskingSelector) sym else NoSymbol + if (hasMaskingSelector && defn.RootImportTypes.exists(_.symbol == sym)) sym + else NoSymbol } override def toString = { diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 148cf1da7..b8fe46745 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -528,18 +528,96 @@ class Namer { typer: Typer => } } - stats foreach expand + stats.foreach(expand) mergeCompanionDefs() val ctxWithStats = (ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx)) createCompanionLinks(ctxWithStats) ctxWithStats } + /** Add all annotations of definitions in `stats` to the defined symbols */ + def annotate(stats: List[Tree])(implicit ctx: Context): Unit = { + def recur(stat: Tree): Unit = stat match { + case pcl: PackageDef => + annotate(pcl.stats) + case stat: untpd.MemberDef => + stat.getAttachment(SymOfTree) match { + case Some(sym) => + sym.infoOrCompleter match { + case info: Completer if !defn.isPredefClass(sym.owner) => + // Annotate Predef methods only when they are completed; + // This is necessary to break a cyclic dependence between `Predef` + // and `deprecated` in test `compileStdLib`. + addAnnotations(sym, stat)(info.creationContext) + case _ => + // Annotations were already added as part of the symbol's completion + } + case none => + assert(stat.typeOpt.exists, i"no symbol for $stat") + } + case stat: untpd.Thicket => + stat.trees.foreach(recur) + case _ => + } + + for (stat <- stats) recur(expanded(stat)) + } + + /** Add annotations of `stat` to `sym`. + * This method can be called twice on a symbol (e.g. once + * during the `annotate` phase and then again during completion). + * Therefore, care needs to be taken not to add annotations again + * that are already added to the symbol. + */ + def addAnnotations(sym: Symbol, stat: MemberDef)(implicit ctx: Context) = { + // (1) The context in which an annotation of a top-level class or module is evaluated + // is the closest enclosing context which has the enclosing package as owner. + // (2) The context in which an annotation for any other symbol is evaluated is the + // closest enclosing context which has the owner of the class enclosing the symbol as owner. + // E.g in + // + // package p + // import a.b + // class C { + // import d.e + // @ann m() ... + // } + // + // `@ann` is evaluated in the context just outside `C`, where the `a.b` + // import is visible but the `d.e` import is forgotten. This measure is necessary + // in order to avoid cycles. + lazy val annotCtx = { + var target = sym.owner.lexicallyEnclosingClass + if (!target.is(PackageClass)) target = target.owner + var c = ctx + while (c.owner != target) c = c.outer + c + } + for (annotTree <- untpd.modsDeco(stat).mods.annotations) { + val cls = typedAheadAnnotation(annotTree)(annotCtx) + if (sym.unforcedAnnotation(cls).isEmpty) { + val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree)) + sym.addAnnotation(ann) + if (cls == defn.InlineAnnot && sym.is(Method, butNot = Accessor)) + sym.setFlag(Inline) + } + } + } + + def indexAndAnnotate(stats: List[Tree])(implicit ctx: Context): Context = { + val localCtx = index(stats) + annotate(stats) + localCtx + } + /** The completer of a symbol defined by a member def or import (except ClassSymbols) */ class Completer(val original: Tree)(implicit ctx: Context) extends LazyType { protected def localContext(owner: Symbol) = ctx.fresh.setOwner(owner).setTree(original) + /** The context with which this completer was created */ + def creationContext = ctx + protected def typeSig(sym: Symbol): Type = original match { case original: ValDef => if (sym is Module) moduleValSig(sym) @@ -572,19 +650,6 @@ class Namer { typer: Typer => completeInCreationContext(denot) } - protected def addAnnotations(denot: SymDenotation): Unit = original match { - case original: untpd.MemberDef => - var hasInlineAnnot = false - for (annotTree <- untpd.modsDeco(original).mods.annotations) { - val cls = typedAheadAnnotation(annotTree) - val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree)) - denot.addAnnotation(ann) - if (cls == defn.InlineAnnot && denot.is(Method, butNot = Accessor)) - denot.setFlag(Inline) - } - case _ => - } - private def addInlineInfo(denot: SymDenotation) = original match { case original: untpd.DefDef if denot.isInlineMethod => Inliner.registerInlineInfo( @@ -598,7 +663,10 @@ class Namer { typer: Typer => * to pick up the context at the point where the completer was created. */ def completeInCreationContext(denot: SymDenotation): Unit = { - addAnnotations(denot) + original match { + case original: MemberDef => addAnnotations(denot.symbol, original) + case _ => + } addInlineInfo(denot) denot.info = typeSig(denot.symbol) Checking.checkWellFormed(denot.symbol) @@ -742,7 +810,7 @@ class Namer { typer: Typer => ok } - addAnnotations(denot) + addAnnotations(denot.symbol, original) val selfInfo = if (self.isEmpty) NoType @@ -765,9 +833,10 @@ class Namer { typer: Typer => // accessors, that's why the constructor needs to be completed before // the parent types are elaborated. index(constr) + annotate(constr :: params) symbolOfTree(constr).ensureCompleted() - index(rest)(inClassContext(selfInfo)) + indexAndAnnotate(rest)(inClassContext(selfInfo)) val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_, tparamAccessors))) @@ -790,7 +859,7 @@ class Namer { typer: Typer => case Some(ttree) => ttree case none => val ttree = typer.typed(tree, pt) - xtree.pushAttachment(TypedAhead, ttree) + xtree.putAttachment(TypedAhead, ttree) ttree } } @@ -810,7 +879,7 @@ class Namer { typer: Typer => /** Enter and typecheck parameter list */ def completeParams(params: List[MemberDef])(implicit ctx: Context) = { - index(params) + indexAndAnnotate(params) for (param <- params) typedAheadExpr(param) } @@ -990,7 +1059,7 @@ class Namer { typer: Typer => // 3. Info of CP is computed (to be copied to DP). // 4. CP is completed. // 5. Info of CP is copied to DP and DP is completed. - index(tparams) + indexAndAnnotate(tparams) if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted()) for (tparam <- tparams) typedAheadExpr(tparam) diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 2413c0c22..f0acdef12 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -72,6 +72,7 @@ class ReTyper extends Typer { override def localTyper(sym: Symbol) = this override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx + override def annotate(trees: List[untpd.Tree])(implicit ctx: Context) = () override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree = fallBack(tree, ctx.typerState) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ccc74cfff..4ec1c460f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -27,7 +27,7 @@ import EtaExpansion.etaExpand import dotty.tools.dotc.transform.Erasure.Boxing import util.Positions._ import util.common._ -import util.SourcePosition +import util.{SourcePosition, Property} import collection.mutable import annotation.tailrec import Implicits._ @@ -57,6 +57,8 @@ object Typer { def assertPositioned(tree: untpd.Tree)(implicit ctx: Context) = if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}") + + private val ExprOwner = new Property.Key[Symbol] } class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking with Docstrings { @@ -74,7 +76,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * Note: It would be more proper to move importedFromRoot into typedIdent. * We should check that this has no performance degradation, however. */ - private var importedFromRoot: Set[Symbol] = Set() + private var unimported: Set[Symbol] = Set() /** Temporary data item for single call to typed ident: * This symbol would be found under Scala2 mode, but is not @@ -102,15 +104,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit */ def error(msg: => Message, pos: Position) = ctx.error(msg, pos) - /** Is this import a root import that has been shadowed by an explicit - * import in the same program? - */ - def isDisabled(imp: ImportInfo, site: Type): Boolean = { - if (imp.isRootImport && (importedFromRoot contains site.termSymbol)) return true - if (imp.hiddenRoot.exists) importedFromRoot += imp.hiddenRoot - false - } - /** Does this identifier appear as a constructor of a pattern? */ def isPatternConstr = if (ctx.mode.isExpr && (ctx.outer.mode is Mode.Pattern)) @@ -188,32 +181,44 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit /** The type representing a named import with enclosing name when imported * from given `site` and `selectors`. */ - def namedImportRef(site: Type, selectors: List[untpd.Tree])(implicit ctx: Context): Type = { - def checkUnambiguous(found: Type) = { - val other = namedImportRef(site, selectors.tail) - if (other.exists && found.exists && (found != other)) - error(em"reference to `$name` is ambiguous; it is imported twice in ${ctx.tree}", - tree.pos) - found - } + def namedImportRef(imp: ImportInfo)(implicit ctx: Context): Type = { val Name = name.toTermName.decode - selectors match { + def recur(selectors: List[untpd.Tree]): Type = selectors match { case selector :: rest => + def checkUnambiguous(found: Type) = { + val other = recur(selectors.tail) + if (other.exists && found.exists && (found != other)) + error(em"reference to `$name` is ambiguous; it is imported twice in ${ctx.tree}", + tree.pos) + found + } + + def selection(name: Name) = + if (imp.sym.isCompleting) { + ctx.warning(i"cyclic ${imp.sym}, ignored", tree.pos) + NoType + } + else if (unimported.nonEmpty && unimported.contains(imp.site.termSymbol)) + NoType + else { + // Pass refctx so that any errors are reported in the context of the + // reference instead of the + checkUnambiguous(selectionType(imp.site, name, tree.pos)(refctx)) + } + selector match { case Thicket(fromId :: Ident(Name) :: _) => val Ident(from) = fromId - val selName = if (name.isTypeName) from.toTypeName else from - // Pass refctx so that any errors are reported in the context of the - // reference instead of the context of the import. - checkUnambiguous(selectionType(site, selName, tree.pos)(refctx)) + selection(if (name.isTypeName) from.toTypeName else from) case Ident(Name) => - checkUnambiguous(selectionType(site, name, tree.pos)(refctx)) + selection(name) case _ => - namedImportRef(site, rest) + recur(rest) } case nil => NoType } + recur(imp.selectors) } /** The type representing a wildcard import with enclosing name when imported @@ -222,7 +227,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def wildImportRef(imp: ImportInfo)(implicit ctx: Context): Type = { if (imp.isWildcardImport) { val pre = imp.site - if (!isDisabled(imp, pre) && !(imp.excluded contains name.toTermName) && name != nme.CONSTRUCTOR) { + if (!unimported.contains(pre.termSymbol) && + !imp.excluded.contains(name.toTermName) && + name != nme.CONSTRUCTOR) { val denot = pre.member(name).accessibleFrom(pre)(refctx) if (reallyExists(denot)) return pre.select(name, denot) } @@ -279,19 +286,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (result.exists) result else { // find import val curImport = ctx.importInfo + def updateUnimported() = + if (curImport.unimported.exists) unimported += curImport.unimported if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) previous // no more conflicts possible in this case - else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && !curImport.sym.isCompleting) { - val namedImp = namedImportRef(curImport.site, curImport.selectors) + else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo)) { + val namedImp = namedImportRef(curImport) if (namedImp.exists) findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer) - else if (isPossibleImport(wildImport)) { + else if (isPossibleImport(wildImport) && !curImport.sym.isCompleting) { val wildImp = wildImportRef(curImport) if (wildImp.exists) findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer) - else loop(outer) + else { + updateUnimported() + loop(outer) + } + } + else { + updateUnimported() + loop(outer) } - else loop(outer) } else loop(outer) } @@ -311,11 +326,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit return typed(desugar.patternVar(tree), pt) } - val rawType = { - val saved1 = importedFromRoot + val saved1 = unimported val saved2 = foundUnderScala2 - importedFromRoot = Set.empty + unimported = Set.empty foundUnderScala2 = NoType try { var found = findRef(NoType, BindingPrec.nothingBound, NoContext) @@ -329,7 +343,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit found } finally { - importedFromRoot = saved1 + unimported = saved1 foundUnderScala2 = saved2 } } @@ -576,7 +590,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } def typedBlockStats(stats: List[untpd.Tree])(implicit ctx: Context): (Context, List[tpd.Tree]) = - (index(stats), typedStats(stats, ctx.owner)) + (indexAndAnnotate(stats), typedStats(stats, ctx.owner)) def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") { val (exprCtx, stats1) = typedBlockStats(tree.stats) @@ -1058,7 +1072,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedPolyTypeTree(tree: untpd.PolyTypeTree)(implicit ctx: Context): Tree = track("typedPolyTypeTree") { val PolyTypeTree(tparams, body) = tree - index(tparams) + indexAndAnnotate(tparams) val tparams1 = tparams.mapconserve(typed(_).asInstanceOf[TypeDef]) val body1 = typedType(tree.body) assignType(cpy.PolyTypeTree(tree)(tparams1, body1), tparams1, body1) @@ -1121,7 +1135,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = { // necessary to force annotation trees to be computed. sym.annotations.foreach(_.ensureCompleted) - val annotCtx = ctx.outersIterator.dropWhile(_.owner == sym).next + lazy val annotCtx = { + val c = ctx.outersIterator.dropWhile(_.owner == sym).next + c.property(ExprOwner) match { + case Some(exprOwner) if c.owner.isClass => + // We need to evaluate annotation arguments in an expression context, since + // classes defined in a such arguments should not be entered into the + // enclosing class. + c.exprContext(mdef, exprOwner) + case None => c + } + } // necessary in order to mark the typed ahead annotations as definitely typed: untpd.modsDeco(mdef).mods.annotations.foreach(typedAnnotation(_)(annotCtx)) } @@ -1540,7 +1564,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case nil => buf.toList } - traverse(stats) + val localCtx = { + val exprOwnerOpt = if (exprOwner == ctx.owner) None else Some(exprOwner) + ctx.withProperty(ExprOwner, exprOwnerOpt) + } + traverse(stats)(localCtx) } /** Given an inline method `mdef`, the method rewritten so that its body diff --git a/compiler/src/dotty/tools/dotc/util/Chars.scala b/compiler/src/dotty/tools/dotc/util/Chars.scala index bae3b4732..6f95b87c4 100644 --- a/compiler/src/dotty/tools/dotc/util/Chars.scala +++ b/compiler/src/dotty/tools/dotc/util/Chars.scala @@ -6,7 +6,6 @@ package dotty.tools.dotc package util import scala.annotation.switch -import java.lang.{ Character => JCharacter } import java.lang.{Character => JCharacter} import java.lang.Character.LETTER_NUMBER import java.lang.Character.LOWERCASE_LETTER @@ -66,16 +65,16 @@ object Chars { /** Can character start an alphanumeric Scala identifier? */ def isIdentifierStart(c: Char): Boolean = - (c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c) + (c == '_') || (c == '$') || JCharacter.isUnicodeIdentifierStart(c) /** Can character form part of an alphanumeric Scala identifier? */ def isIdentifierPart(c: Char) = - (c == '$') || Character.isUnicodeIdentifierPart(c) + (c == '$') || JCharacter.isUnicodeIdentifierPart(c) /** Is character a math or other symbol in Unicode? */ def isSpecial(c: Char) = { - val chtp = Character.getType(c) - chtp == Character.MATH_SYMBOL.toInt || chtp == Character.OTHER_SYMBOL.toInt + val chtp = JCharacter.getType(c) + chtp == JCharacter.MATH_SYMBOL.toInt || chtp == JCharacter.OTHER_SYMBOL.toInt } private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_' diff --git a/tests/neg/i1647.scala b/tests/neg/i1647.scala new file mode 100644 index 000000000..b6910cc70 --- /dev/null +++ b/tests/neg/i1647.scala @@ -0,0 +1,4 @@ +class ann { + @ann({ def baz }) // error: missing return type + def foo(): Unit +} diff --git a/tests/neg/i1649.scala b/tests/neg/i1649.scala new file mode 100644 index 000000000..e60a2376a --- /dev/null +++ b/tests/neg/i1649.scala @@ -0,0 +1,2 @@ +class Two[@A A] // error + diff --git a/tests/neg/nopredef.scala b/tests/neg/nopredef.scala new file mode 100644 index 000000000..0079be41e --- /dev/null +++ b/tests/neg/nopredef.scala @@ -0,0 +1,5 @@ +import Predef.{assert => _} + +object Test { + assert("asdf" == "asdf") // error: not found assert +} |