diff options
Diffstat (limited to 'compiler')
28 files changed, 204 insertions, 104 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index deb239143..b5be89440 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -469,7 +469,13 @@ object desugar { val originalVparams = constr1.vparamss.toIterator.flatten val tparamAccessors = derivedTparams.map(_.withMods(originalTparams.next.mods)) val caseAccessor = if (isCaseClass) CaseAccessor else EmptyFlags - val vparamAccessors = derivedVparamss.flatten.map(_.withMods(originalVparams.next.mods | caseAccessor)) + val vparamAccessors = derivedVparamss match { + case first :: rest => + first.map(_.withMods(originalVparams.next.mods | caseAccessor)) ++ + rest.flatten.map(_.withMods(originalVparams.next.mods)) + case _ => + Nil + } cpy.TypeDef(cdef)( name = className, rhs = cpy.Template(impl)(constr, parents1, self1, diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 985b1ea3d..5464dce4f 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -117,11 +117,17 @@ object Annotations { } /** Create an annotation where the symbol and the tree are computed lazily. */ - def deferredSymAndTree(sym: => Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation = + def deferredSymAndTree(symf: Context => Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation = new LazyAnnotation { - lazy val symf = sym - - override def symbol(implicit ctx: Context): Symbol = symf + private[this] var mySym: Symbol = _ + + override def symbol(implicit ctx: Context): Symbol = { + if (mySym == null || mySym.defRunId != ctx.runId) { + mySym = symf(ctx) + assert(mySym != null) + } + mySym + } def complete(implicit ctx: Context) = treeFn(ctx) } diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 9e9e39a84..847177e2f 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -9,6 +9,7 @@ import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } import PartialFunction._ import collection.mutable +import util.common.alwaysZero import scala.reflect.api.{ Universe => ApiUniverse } object Definitions { @@ -152,7 +153,7 @@ class Definitions { resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = { val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount) val tparamBounds = tparamNames map (_ => TypeBounds.empty) - val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn) + val ptype = PolyType(tparamNames, tparamNames.map(alwaysZero))(_ => tparamBounds, resultTypeFn) enterMethod(cls, name, ptype, flags) } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 6063cbf38..fca111702 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -489,7 +489,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1 @ MethodType(_, formals1) => (tp1.signature consistentParams tp2.signature) && matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && - (!tp1.isImplicit || tp2.isImplicit) && // non-implicit functions shadow implicit ones + (tp1.isImplicit == tp2.isImplicit) && isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) case _ => false diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index c2a7d7ea6..308e6e306 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -401,12 +401,12 @@ trait TypeOps { this: Context => // TODO: Make standalone object. def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match { case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 => for (pref <- prefs) { - def forward(): Unit = + def forward()(implicit ctx: Context): Unit = for (argSym <- pref.decls) if (argSym is BaseTypeArg) forwardRef(argSym, from, to, cls, decls) pref.info match { - case info: TempClassInfo => info.addSuspension(forward) + case info: TempClassInfo => info.addSuspension(implicit ctx => forward()) case _ => forward() } } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ae9122853..200e94a1e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2603,7 +2603,7 @@ object Types { case t => mapOver(t) } } - PolyType(paramNames ++ that.paramNames)( + PolyType(paramNames ++ that.paramNames, variances ++ that.variances)( x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++ that.paramBounds.mapConserve(shift(_).subst(that, x).bounds), x => shift(that.resultType).subst(that, x).subst(this, x)) @@ -2634,11 +2634,10 @@ object Types { } object PolyType { - def apply(paramNames: List[TypeName], variances: List[Int] = Nil)( + def apply(paramNames: List[TypeName], variances: List[Int])( paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = { - val vs = if (variances.isEmpty) paramNames.map(alwaysZero) else variances - unique(new PolyType(paramNames, vs)(paramBoundsExp, resultTypeExp)) + unique(new PolyType(paramNames, variances)(paramBoundsExp, resultTypeExp)) } def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] = @@ -3089,14 +3088,14 @@ object Types { * be no longer temporary. These actions will be performed once `cls` gets a real * ClassInfo. */ - private var suspensions: List[() => Unit] = Nil + private var suspensions: List[Context => Unit] = Nil - def addSuspension(suspension: () => Unit): Unit = suspensions ::= suspension + def addSuspension(suspension: Context => Unit): Unit = suspensions ::= suspension /** Install classinfo with known parents in `denot` and resume all suspensions */ def finalize(denot: SymDenotation, parents: List[TypeRef])(implicit ctx: Context) = { denot.info = derivedClassInfo(classParents = parents) - suspensions.foreach(_()) + suspensions.foreach(_(ctx)) } } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 5b751ef3c..36d478c6d 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -806,7 +806,7 @@ class ClassfileParser( def classSymbol(externalName: Name)(implicit ctx: Context): Symbol = { /** Return the symbol of `innerName`, having the given `externalName`. */ def innerSymbol(externalName: Name, innerName: Name, static: Boolean): Symbol = { - def getMember(sym: Symbol, name: Name): Symbol = + def getMember(sym: Symbol, name: Name)(implicit ctx: Context): Symbol = if (static) if (sym == classRoot.symbol) staticScope.lookup(name) else sym.companionModule.info.member(name).symbol diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index ffd594454..fcba957c0 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -554,7 +554,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val end = readEnd() val tp = readType() val lazyAnnotTree = readLater(end, rdr => ctx => rdr.readTerm()(ctx)) - annots += Annotation.deferredSymAndTree(tp.typeSymbol, _ => lazyAnnotTree.complete) + annots += Annotation.deferredSymAndTree( + implicit ctx => tp.typeSymbol, + implicit ctx => lazyAnnotTree.complete) case tag => assert(false, s"illegal modifier tag $tag at $currentAddr, end = $end") } @@ -769,7 +771,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle cls.setApplicableFlags(fork.indexStats(end)) val constr = readIndexedDef().asInstanceOf[DefDef] - def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree]): (List[Tree], List[Tree]) = + def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) = (tparams, stats) match { case (tparam :: tparams1, (alias: TypeDef) :: stats1) if tparam.name == alias.name.expandedName(cls) => diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index b01f6cc6a..3a2a45fd2 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -932,9 +932,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas protected def deferredAnnot(end: Int)(implicit ctx: Context): Annotation = { val start = readIndex val atp = readTypeRef() + val phase = ctx.phase Annotation.deferred( - atp.typeSymbol, implicit ctx1 => - atReadPos(start, () => readAnnotationContents(end)(ctx1.withPhase(ctx.phase)))) + atp.typeSymbol, implicit ctx => + atReadPos(start, () => readAnnotationContents(end)(ctx.withPhase(phase)))) } /* Read an abstract syntax tree */ diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index b46bc401d..c14108d2e 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -993,20 +993,22 @@ object Parsers { else { val saved = placeholderParams placeholderParams = Nil + + def wrapPlaceholders(t: Tree) = try + if (placeholderParams.isEmpty) t + else new WildcardFunction(placeholderParams.reverse, t) + finally placeholderParams = saved + val t = expr1(location) if (in.token == ARROW) { - placeholderParams = saved - closureRest(start, location, convertToParams(t)) + placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder + wrapPlaceholders(closureRest(start, location, convertToParams(t))) } else if (isWildcard(t)) { placeholderParams = placeholderParams ::: saved t } - else - try - if (placeholderParams.isEmpty) t - else new WildcardFunction(placeholderParams.reverse, t) - finally placeholderParams = saved + else wrapPlaceholders(t) } } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index ac25f7cfd..0d1068b8c 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -7,6 +7,7 @@ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annot import StdNames.{nme, tpnme} import ast.Trees._, ast._ import typer.Implicits._ +import typer.ImportInfo import config.Config import java.lang.Integer.toOctalString import config.Config.summarizeDepth @@ -177,7 +178,8 @@ class PlainPrinter(_ctx: Context) extends Printer { varianceString(variance) ~ name.toString ~ toText(bounds) changePrec(GlobalPrec) { "[" ~ Text((tp.variances, tp.paramNames, tp.paramBounds).zipped.map(paramText), ", ") ~ - "] => " ~ toTextGlobal(tp.resultType) + "]" ~ (" => " provided !tp.resultType.isInstanceOf[MethodType]) ~ + toTextGlobal(tp.resultType) } case tp: PolyParam => polyParamNameString(tp) ~ polyHash(tp.binder) @@ -502,6 +504,17 @@ class PlainPrinter(_ctx: Context) extends Printer { "?Unknown Implicit Result?" } + def toText(importInfo: ImportInfo): Text = { + val siteStr = importInfo.site.show + val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr + val selectorStr = importInfo.selectors match { + case Ident(name) :: Nil => name.show + case _ => "{...}" + } + s"import $exprStr.$selectorStr" + } + + private var maxSummarized = Int.MaxValue def summarized[T](depth: Int)(op: => T): T = { diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index 506773a4b..e163a83f3 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -6,6 +6,7 @@ import Texts._, ast.Trees._ import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant, Names.Name, Denotations._, Annotations.Annotation import typer.Implicits.SearchResult +import typer.ImportInfo /** The base class of all printers */ @@ -98,6 +99,9 @@ abstract class Printer { /** Textual representation of implicit search result */ def toText(result: SearchResult): Text + /** Textual representation of info relating to an import clause */ + def toText(result: ImportInfo): Text + /** Perform string or text-producing operation `op` so that only a * summarized text with given recursion depth is shown */ diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 26c1e5ebc..b2c7abec9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -171,22 +171,6 @@ trait Reporting { this: Context => throw ex } } - - /** Implements a fold that applies the function `f` to the result of `op` if - * there are no new errors in the reporter - * - * @param op operation checked for errors - * @param f function applied to result of op - * @return either the result of `op` if it had errors or the result of `f` - * applied to it - */ - def withNoError[A, B >: A](op: => A)(f: A => B): B = { - val before = reporter.errorCount - val op0 = op - - if (reporter.errorCount > before) op0 - else f(op0) - } } /** diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index c74130b44..2bf15cb7c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -49,7 +49,9 @@ public enum ErrorMessageID { OverridesNothingButNameExistsID, ForwardReferenceExtendsOverDefinitionID, ExpectedTokenButFoundID, - MixedLeftAndRightAssociativeOpsID; + MixedLeftAndRightAssociativeOpsID, + CantInstantiateAbstractClassOrTraitID, + ; public int errorNumber() { return ordinal() - 2; diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 7fccebef9..34190c114 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1062,7 +1062,7 @@ object messages { | |Define `${definition.name}` before it is used, |or move the definition of `${value.name}` so it does not appear between - |the declartion of `${definition.name}` and its use, + |the declaration of `${definition.name}` and its use, |or define `${value.name}` as lazy. |""".stripMargin } @@ -1127,4 +1127,23 @@ object messages { |""".stripMargin } + case class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) + extends Message(CantInstantiateAbstractClassOrTraitID) { + val kind = "Usage" + private val traitOrAbstract = if (isTrait) hl"a trait" else hl"abstract" + val msg = hl"""${cls.name} is ${traitOrAbstract}; it cannot be instantiated""" + val explanation = + hl"""|Abstract classes and traits need to be extended by a concrete class or object + |to make their functionality accessible. + | + |You may want to create an anonymous class extending ${cls.name} with + | ${s"class ${cls.name} { }"} + | + |or add a companion object with + | ${s"object ${cls.name} extends ${cls.name}"} + | + |You need to implement any abstract members in both cases. + |""".stripMargin + } + } diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index 6c69c735b..9e43fc999 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -101,6 +101,7 @@ trait FullParameterization { } val ctparams = if (abstractOverClass) clazz.typeParams else Nil val ctnames = ctparams.map(_.name.unexpandedName) + val ctvariances = ctparams.map(_.variance) /** The method result type */ def resultType(mapClassParams: Type => Type) = { @@ -122,14 +123,14 @@ trait FullParameterization { info match { case info: PolyType => - PolyType(info.paramNames ++ ctnames)( + PolyType(info.paramNames ++ ctnames, info.variances ++ ctvariances)( pt => (info.paramBounds.map(mapClassParams(_, pt).bounds) ++ mappedClassBounds(pt)).mapConserve(_.subst(info, pt).bounds), pt => resultType(mapClassParams(_, pt)).subst(info, pt)) case _ => if (ctparams.isEmpty) resultType(identity) - else PolyType(ctnames)(mappedClassBounds, pt => resultType(mapClassParams(_, pt))) + else PolyType(ctnames, ctvariances)(mappedClassBounds, pt => resultType(mapClassParams(_, pt))) } } diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 3e7a7ed89..aa0845605 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -119,7 +119,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete // now this speculatively transforms tree and throws away result in many cases val rhsSemiTransformed = { val transformer = new TailRecElimination(origMeth, dd.tparams, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel) - val rhs = atGroupEnd(transformer.transform(dd.rhs)(_)) + val rhs = atGroupEnd(implicit ctx => transformer.transform(dd.rhs)) rewrote = transformer.rewrote rhs } 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. diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 7af903364..a720f1294 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -184,6 +184,7 @@ class tests extends CompilerTest { @Test def neg_autoTupling = compileFile(negCustomArgs, "autoTuplingTest", args = "-language:noAutoTupling" :: Nil) @Test def neg_i1050 = compileFile(negCustomArgs, "i1050", List("-strict")) @Test def neg_i1240 = compileFile(negCustomArgs, "i1240")(allowDoubleBindings) + @Test def neg_i2002 = compileFile(negCustomArgs, "i2002")(allowDoubleBindings) val negTailcallDir = negDir + "tailcall/" @Test def neg_tailcall_t1672b = compileFile(negTailcallDir, "t1672b") diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 37d1404bb..971a40a1b 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -159,4 +159,43 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals("+:", op2.show) assertFalse(op2LeftAssoc) } + + @Test def cantInstantiateAbstract = + checkMessagesAfter("refchecks") { + """ + |object Scope { + | abstract class Concept + | new Concept() + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + assertMessageCount(1, messages) + val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages + assertEquals("Concept", cls.name.show) + assertFalse("expected class", isTrait) + } + + @Test def cantInstantiateTrait = + checkMessagesAfter("refchecks") { + """ + |object Scope { + | trait Concept + | new Concept() + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + assertMessageCount(1, messages) + val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages + assertEquals("Concept", cls.name.show) + assertTrue("expected trait", isTrait) + } + } |