diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc')
76 files changed, 1119 insertions, 649 deletions
diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 1d319242b..f413fc902 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -48,9 +48,9 @@ class Compiler { List(new Pickler), // Generate TASTY info List(new FirstTransform, // Some transformations to put trees into a canonical form new CheckReentrant), // Internal use only: Check that compiled program has no data races involving global vars - List(new RefChecks, // Various checks mostly related to abstract members and overriding - new CheckStatic, // Check restrictions that apply to @static members + List(new CheckStatic, // Check restrictions that apply to @static members new ElimRepeated, // Rewrite vararg parameters and arguments + new RefChecks, // Various checks mostly related to abstract members and overriding new NormalizeFlags, // Rewrite some definition flags new ExtensionMethods, // Expand methods of value classes with extension methods new ExpandSAMs, // Expand single abstract method closures to anonymous classes diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index e48b1039b..b00d7df71 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -26,18 +26,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case _ => false } - /** The largest subset of {NoInits, PureInterface} that a - * trait enclosing this statement can have as flags. - * Does tree contain an initialization part when seen as a member of a class or trait? - */ - def defKind(tree: Tree): FlagSet = unsplice(tree) match { - case EmptyTree | _: Import => NoInitsInterface - case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface - case tree: DefDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else NoInits - case tree: ValDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else EmptyFlags - case _ => EmptyFlags - } - def isOpAssign(tree: Tree) = unsplice(tree) match { case Apply(fn, _ :: _) => unsplice(fn) match { @@ -583,6 +571,16 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => accum(Nil, root) } + /** The largest subset of {NoInits, PureInterface} that a + * trait enclosing this statement can have as flags. + */ + def defKind(tree: Tree): FlagSet = unsplice(tree) match { + case EmptyTree | _: Import => NoInitsInterface + case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface + case tree: DefDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else NoInits + case tree: ValDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else EmptyFlags + case _ => EmptyFlags + } /** The top level classes in this tree, including only those module classes that * are not a linked class of some other class in the result. diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 27be8c9d6..669e5429c 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -712,8 +712,11 @@ object Trees { override def toList: List[Tree[T]] = flatten(trees) override def toString = if (isEmpty) "EmptyTree" else "Thicket(" + trees.mkString(", ") + ")" override def withPos(pos: Position): this.type = { - val newTrees = trees.map(_.withPos(pos)) - new Thicket[T](newTrees).asInstanceOf[this.type] + val newTrees = trees.mapConserve(_.withPos(pos)) + if (trees eq newTrees) + this + else + new Thicket[T](newTrees).asInstanceOf[this.type] } override def pos = (NoPosition /: trees) ((pos, t) => pos union t.pos) override def foreachInThicket(op: Tree[T] => Unit): Unit = diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 458e94b6e..cbb256dd0 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -185,12 +185,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp match { - case tp @ MethodType(paramNames, paramTypes) => + case tp: MethodType => def valueParam(name: TermName, info: Type): TermSymbol = { val maybeImplicit = if (tp.isInstanceOf[ImplicitMethodType]) Implicit else EmptyFlags ctx.newSymbol(sym, name, TermParam | maybeImplicit, info) } - val params = (paramNames, paramTypes).zipped.map(valueParam) + val params = (tp.paramNames, tp.paramTypes).zipped.map(valueParam) val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.termRef))) (params :: paramss, rtp) case tp => (Nil, tp.widenExpr) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 99bc3240f..8ca91590f 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -149,6 +149,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def is(fs: FlagSet): Boolean = flags is fs def is(fc: FlagConjunction): Boolean = flags is fc + def is(fc: FlagSet, butNot: FlagSet): Boolean = flags.is(fc, butNot = butNot) def | (fs: FlagSet): Modifiers = withFlags(flags | fs) def & (fs: FlagSet): Modifiers = withFlags(flags & fs) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 119af9483..903efd794 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -75,10 +75,23 @@ object Config { /** If this flag is set, take the fast path when comparing same-named type-aliases and types */ final val fastPathForRefinedSubtype = true + /** If this flag is set, and we compute `T1 { X = S1 }` & `T2 { X = S2 }` as a new + * upper bound of a constrained parameter, try to align the refinements by computing + * `S1 =:= S2` (which might instantiate type parameters). + * This rule is contentious because it cuts the constraint set. + * + * For more info, see the comment in `TypeComparer#distributeAnd`. + */ + final val alignArgsInAnd = true + /** If this flag is set, higher-kinded applications are checked for validity */ final val checkHKApplications = false + /** If this flag is set, method types are checked for valid parameter references + */ + final val checkMethodTypes = false + /** The recursion depth for showing a summarized string */ final val summarizeDepth = 2 diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala index 59201687a..8bc18c387 100644 --- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -23,7 +23,7 @@ class JavaPlatform extends Platform { // The given symbol is a method with the right name and signature to be a runnable java program. def isJavaMainMethod(sym: SymDenotation)(implicit ctx: Context) = (sym.name == nme.main) && (sym.info match { - case t@MethodType(_, defn.ArrayOf(el) :: Nil) => el =:= defn.StringType && (t.resultType isRef defn.UnitClass) + case MethodTpe(_, defn.ArrayOf(el) :: Nil, restpe) => el =:= defn.StringType && (restpe isRef defn.UnitClass) case _ => false }) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index fd79fcaa6..40e2b083b 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -1,6 +1,8 @@ package dotty.tools.dotc package config +import java.io.File + import PathResolver.Defaults import rewrite.Rewrites @@ -111,7 +113,7 @@ class ScalaSettings extends Settings.SettingGroup { "-project", "project title", "The name of the project", - sys.props("user.dir").split(sys.props("file.separator")).last + sys.props("user.dir").split(File.separatorChar).last ) val wikiSyntax = BooleanSetting("-Xwiki-syntax", "Retains the Scala2 behavior of using Wiki Syntax in Scaladoc") diff --git a/compiler/src/dotty/tools/dotc/config/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index c2763cdf0..264388c03 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -3,7 +3,6 @@ package config import collection.mutable.{ ArrayBuffer } import scala.util.{ Try, Success, Failure } -import scala.reflect.internal.util.StringOps import reflect.ClassTag import core.Contexts._ import scala.annotation.tailrec diff --git a/compiler/src/dotty/tools/dotc/core/Constraint.scala b/compiler/src/dotty/tools/dotc/core/Constraint.scala index c99b748b7..50136a26c 100644 --- a/compiler/src/dotty/tools/dotc/core/Constraint.scala +++ b/compiler/src/dotty/tools/dotc/core/Constraint.scala @@ -111,12 +111,6 @@ abstract class Constraint extends Showable { */ def replace(param: PolyParam, tp: Type)(implicit ctx: Context): This - /** Narrow one of the bounds of type parameter `param` - * If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure - * that `param >: bound`. - */ - def narrowBound(param: PolyParam, bound: Type, isUpper: Boolean)(implicit ctx: Context): This - /** Is entry associated with `pt` removable? This is the case if * all type parameters of the entry are associated with type variables * which have their `inst` fields set. diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 3aa20f15b..2a1f4ee6e 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -44,6 +44,13 @@ trait ConstraintHandling { try op finally alwaysFluid = saved } + /** If set, align arguments `S1`, `S2`when taking the glb + * `T1 { X = S1 } & T2 { X = S2 }` of a constraint upper bound for some type parameter. + * Aligning means computing `S1 =:= S2` which may change the current constraint. + * See note in TypeComparer#distributeAnd. + */ + protected var homogenizeArgs = false + /** We are currently comparing polytypes. Used as a flag for * optimization: when `false`, no need to do an expensive `pruneLambdaParams` */ @@ -64,7 +71,8 @@ trait ConstraintHandling { } if (Config.checkConstraintsSeparated) assert(!occursIn(bound), s"$param occurs in $bound") - val c1 = constraint.narrowBound(param, bound, isUpper) + val newBound = narrowedBound(param, bound, isUpper) + val c1 = constraint.updateEntry(param, newBound) (c1 eq constraint) || { constraint = c1 val TypeBounds(lo, hi) = constraint.entry(param) @@ -72,6 +80,20 @@ trait ConstraintHandling { } } + /** Narrow one of the bounds of type parameter `param` + * If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure + * that `param >: bound`. + */ + def narrowedBound(param: PolyParam, bound: Type, isUpper: Boolean)(implicit ctx: Context): TypeBounds = { + val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param) + val saved = homogenizeArgs + homogenizeArgs = Config.alignArgsInAnd + try + if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound) + else oldBounds.derivedTypeBounds(lo | bound, hi) + finally homogenizeArgs = saved + } + protected def addUpperBound(param: PolyParam, bound: Type): Boolean = { def description = i"constraint $param <: $bound to\n$constraint" if (bound.isRef(defn.NothingClass) && ctx.typerState.isGlobalCommittable) { @@ -253,9 +275,6 @@ trait ConstraintHandling { if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound)) inst = ctx.harmonizeUnion(inst) - // 3. If instance is from below, and upper bound has open named parameters - // make sure the instance has all named parameters of the bound. - if (fromBelow) inst = inst.widenToNamedTypeParams(param.namedTypeParams) inst } diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index a105741f5..f8267072e 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -15,12 +15,22 @@ import printing.Formatting._ object Decorators { /** Turns Strings into PreNames, adding toType/TermName methods */ - implicit class StringDecorator(val s: String) extends AnyVal with PreName { + implicit class PreNamedString(val s: String) extends AnyVal with PreName { def toTypeName: TypeName = typeName(s) def toTermName: TermName = termName(s) def toText(printer: Printer): Text = Str(s) } + implicit class StringDecorator(val s: String) extends AnyVal { + def splitWhere(f: Char => Boolean, doDropIndex: Boolean): Option[(String, String)] = { + def splitAt(idx: Int, doDropIndex: Boolean): Option[(String, String)] = + if (idx == -1) None + else Some((s.take(idx), s.drop(if (doDropIndex) idx + 1 else idx))) + + splitAt(s.indexWhere(f), doDropIndex) + } + } + /** Implements a findSymbol method on iterators of Symbols that * works like find but avoids Option, replacing None with NoSymbol. */ diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 79e97becb..4d4350f98 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -10,7 +10,6 @@ import scala.collection.{ mutable, immutable } import PartialFunction._ import collection.mutable import util.common.alwaysZero -import scala.reflect.api.{ Universe => ApiUniverse } object Definitions { @@ -300,6 +299,8 @@ class Definitions { lazy val ScalaPredefModuleRef = ctx.requiredModuleRef("scala.Predef") def ScalaPredefModule(implicit ctx: Context) = ScalaPredefModuleRef.symbol + lazy val Predef_ConformsR = ScalaPredefModule.requiredClass("$less$colon$less").typeRef + def Predef_Conforms(implicit ctx: Context) = Predef_ConformsR.symbol lazy val Predef_conformsR = ScalaPredefModule.requiredMethodRef("$conforms") def Predef_conforms(implicit ctx: Context) = Predef_conformsR.symbol lazy val Predef_classOfR = ScalaPredefModule.requiredMethodRef("classOf") @@ -337,6 +338,8 @@ class Definitions { def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol def Predef_eqAny(implicit ctx: Context) = DottyPredefModule.requiredMethod(nme.eqAny) + lazy val Predef_ImplicitConverterR = DottyPredefModule.requiredClass("ImplicitConverter").typeRef + def Predef_ImplicitConverter(implicit ctx: Context) = Predef_ImplicitConverterR.symbol lazy val DottyArraysModuleRef = ctx.requiredModuleRef("dotty.runtime.Arrays") def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol @@ -352,6 +355,7 @@ class Definitions { enterCompleteClassSymbol( ScalaPackageClass, tpnme.Singleton, PureInterfaceCreationFlags | Final, List(AnyClass.typeRef), EmptyScope) + def SingletonType = SingletonClass.typeRef lazy val SeqType: TypeRef = ctx.requiredClassRef("scala.collection.Seq") def SeqClass(implicit ctx: Context) = SeqType.symbol.asClass diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 99c688d50..f726cd0d1 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -308,13 +308,13 @@ object Denotations { case tp2: TypeBounds if tp2 contains tp1 => tp1 case _ => mergeConflict(tp1, tp2) } - case tp1 @ MethodType(names1, formals1) if isTerm => + case tp1: MethodType if isTerm => tp2 match { - case tp2 @ MethodType(names2, formals2) if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + case tp2: MethodType if ctx.typeComparer.matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && tp1.isImplicit == tp2.isImplicit => tp1.derivedMethodType( - mergeNames(names1, names2, nme.syntheticParamName), - formals1, + mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName), + tp1.paramTypes, infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) case _ => mergeConflict(tp1, tp2) @@ -471,14 +471,14 @@ object Denotations { case tp2: TypeBounds if tp2 contains tp1 => tp2 case _ => mergeConflict(tp1, tp2) } - case tp1 @ MethodType(names1, formals1) => + case tp1: MethodType => tp2 match { - case tp2 @ MethodType(names2, formals2) - if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + case tp2: MethodType + if ctx.typeComparer.matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && tp1.isImplicit == tp2.isImplicit => tp1.derivedMethodType( - mergeNames(names1, names2, nme.syntheticParamName), - formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1)) + mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName), + tp1.paramTypes, tp1.resultType | tp2.resultType.subst(tp2, tp1)) case _ => mergeConflict(tp1, tp2) } diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 63fbc98dc..c1267d8a2 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -287,9 +287,10 @@ object Flags { /** A trait that has only abstract methods as members - * (and therefore can be represented by a Java interface + * and therefore can be represented by a Java interface. + * Warning: flag is set during regular typer pass, should be tested only after typer. */ - final val PureInterface = typeFlag(22, "interface") // TODO when unpickling, reconstitute from context + final val PureInterface = typeFlag(22, "interface") /** Labeled with of abstract & override */ final val AbsOverride = termFlag(22, "abstract override") @@ -338,7 +339,9 @@ object Flags { final val JavaStaticTerm = JavaStatic.toTermFlags final val JavaStaticType = JavaStatic.toTypeFlags - /** Trait does not have fields or initialization code */ + /** Trait does not have fields or initialization code. + * Warning: flag is set during regular typer pass, should be tested only after typer. + */ final val NoInits = typeFlag(32, "<noInits>") /** Variable is accessed from nested function. */ @@ -613,9 +616,6 @@ object Flags { /** A private parameter accessor */ final val PrivateParamAccessor = allOf(Private, ParamAccessor) - /** A type parameter introduced with [type ... ] */ - final val NamedTypeParam = allOf(TypeParam, ParamAccessor) - /** A local parameter */ final val ParamAndLocal = allOf(Param, Local) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index aac313892..ea905c19f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -5,7 +5,7 @@ import java.security.MessageDigest import scala.annotation.switch import scala.io.Codec import Names._, StdNames._, Contexts._, Symbols._, Flags._ -import Decorators.StringDecorator +import Decorators.PreNamedString import util.{Chars, NameTransformer} import Chars.isOperatorPart import Definitions._ diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index 72c7a8e51..61dd5a445 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -354,14 +354,6 @@ class OrderingConstraint(private val boundsMap: ParamBounds, updateEntry(p1, p1Bounds).replace(p2, p1) } - def narrowBound(param: PolyParam, bound: Type, isUpper: Boolean)(implicit ctx: Context): This = { - val oldBounds @ TypeBounds(lo, hi) = nonParamBounds(param) - val newBounds = - if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound) - else oldBounds.derivedTypeBounds(lo | bound, hi) - updateEntry(param, newBounds) - } - // ---------- Removals ------------------------------------------------------------ /** A new constraint which is derived from this constraint by removing diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 1e36361f8..5b7dc3d1d 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -7,7 +7,7 @@ import scala.annotation.switch import Names._ import Symbols._ import Contexts._ -import Decorators.StringDecorator +import Decorators.PreNamedString import util.NameTransformer import scala.collection.breakOut @@ -97,6 +97,7 @@ object StdNames { val EMPTY: N = "" val EMPTY_PACKAGE: N = Names.EMPTY_PACKAGE.toString val EVIDENCE_PARAM_PREFIX: N = "evidence$" + val DEP_PARAM_PREFIX = "<param>" val EXCEPTION_RESULT_PREFIX: N = "exceptionResult" val EXPAND_SEPARATOR: N = "$$" val IMPL_CLASS_SUFFIX: N = "$class" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 8e3b73fc0..db96463e0 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -158,7 +158,7 @@ object SymDenotations { final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags } /** Set applicable flags from `flags` which is a subset of {NoInits, PureInterface} */ - final def setApplicableFlags(flags: FlagSet): Unit = { + final def setNoInitsFlags(flags: FlagSet): Unit = { val mask = if (myFlags.is(Trait)) NoInitsInterface else NoInits setFlag(flags & mask) } @@ -957,6 +957,10 @@ object SymDenotations { else companionNamed(name)(ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next) + /** Is this symbol the same or a linked class of `sym`? */ + final def isLinkedWith(sym: Symbol)(implicit ctx: Context): Boolean = + (symbol eq sym) || (linkedClass eq sym) + /** If this is a class, the module class of its companion object. * If this is a module class, its companion class. * NoSymbol otherwise. @@ -1086,9 +1090,6 @@ object SymDenotations { /** The type parameters of a class symbol, Nil for all other symbols */ def typeParams(implicit ctx: Context): List[TypeSymbol] = Nil - /** The named type parameters declared or inherited by this symbol */ - def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = Set() - /** The type This(cls), where cls is this class, NoPrefix for all other symbols */ def thisType(implicit ctx: Context): Type = NoPrefix @@ -1226,11 +1227,9 @@ object SymDenotations { /** TODO: Document why caches are supposedly safe to use */ private[this] var myTypeParams: List[TypeSymbol] = _ - private[this] var myNamedTypeParams: Set[TypeSymbol] = _ - /** The type parameters in this class, in the order they appear in the current * scope `decls`. This might be temporarily the incorrect order when - * reading Scala2 pickled info. The problem is fixed by `updateTypeParams` + * reading Scala2 pickled info. The problem is fixed by `ensureTypeParamsInCorrectOrder`, * which is called once an unpickled symbol has been completed. */ private def typeParamsFromDecls(implicit ctx: Context) = @@ -1253,16 +1252,6 @@ object SymDenotations { myTypeParams } - /** The named type parameters declared or inherited by this class */ - override final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = { - def computeNamedTypeParams: Set[TypeSymbol] = - if (ctx.erasedTypes || is(Module)) Set() // fast return for modules to avoid scanning package decls - else memberNames(abstractTypeNameFilter).map(name => - info.member(name).symbol.asType).filter(_.is(TypeParam, butNot = ExpandedName)).toSet - if (myNamedTypeParams == null) myNamedTypeParams = computeNamedTypeParams - myNamedTypeParams - } - override protected[dotc] final def info_=(tp: Type) = { super.info_=(tp) myTypeParams = null // changing the info might change decls, and with it typeParams diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 4ae28c10b..79f8a6a45 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -12,7 +12,7 @@ import scala.compat.Platform.currentTime import dotty.tools.io.{ ClassPath, AbstractFile } import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util.Positions._, Names._ import StdNames._, NameOps._ -import Decorators.{StringDecorator, StringInterpolators} +import Decorators.{PreNamedString, StringInterpolators} import classfile.ClassfileParser import scala.util.control.NonFatal diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index c5e064478..33aba4d13 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -252,7 +252,7 @@ trait Symbols { this: Context => /** Create a class constructor symbol for given class `cls`. */ def newConstructor(cls: ClassSymbol, flags: FlagSet, paramNames: List[TermName], paramTypes: List[Type], privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) = - newSymbol(cls, nme.CONSTRUCTOR, flags | Method, MethodType(paramNames, paramTypes)(_ => cls.typeRef), privateWithin, coord) + newSymbol(cls, nme.CONSTRUCTOR, flags | Method, MethodType(paramNames, paramTypes, cls.typeRef), privateWithin, coord) /** Create an empty default constructor symbol for given class `cls`. */ def newDefaultConstructor(cls: ClassSymbol) = @@ -496,12 +496,15 @@ object Symbols { final def sourceFile(implicit ctx: Context): AbstractFile = { val file = associatedFile if (file != null && !file.path.endsWith("class")) file - else denot.topLevelClass.getAnnotation(defn.SourceFileAnnot) match { - case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { - case Some(Constant(path: String)) => AbstractFile.getFile(path) + else { + val topLevelCls = denot.topLevelClass(ctx.withPhaseNoLater(ctx.flattenPhase)) + topLevelCls.getAnnotation(defn.SourceFileAnnot) match { + case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { + case Some(Constant(path: String)) => AbstractFile.getFile(path) + case none => null + } case none => null } - case none => null } } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 70819e590..c713cd542 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -246,67 +246,6 @@ class TypeApplications(val self: Type) extends AnyVal { case _ => Nil } - /** The named type parameters declared or inherited by this type. - * These are all uninstantiated named type parameters of this type or one - * of its base types. - */ - final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = self match { - case self: ClassInfo => - self.cls.namedTypeParams - case self: RefinedType => - self.parent.namedTypeParams.filterNot(_.name == self.refinedName) - case self: SingletonType => - Set() - case self: TypeProxy => - self.underlying.namedTypeParams - case _ => - Set() - } - - /** The smallest supertype of this type that instantiated none of the named type parameters - * in `params`. That is, for each named type parameter `p` in `params`, either there is - * no type field named `p` in this type, or `p` is a named type parameter of this type. - * The first case is important for the recursive case of AndTypes, because some of their operands might - * be missing the named parameter altogether, but the AndType as a whole can still - * contain it. - */ - final def widenToNamedTypeParams(params: Set[TypeSymbol])(implicit ctx: Context): Type = { - - /** Is widening not needed for `tp`? */ - def isOK(tp: Type) = { - val ownParams = tp.namedTypeParams - def isMissingOrOpen(param: TypeSymbol) = { - val ownParam = tp.nonPrivateMember(param.name).symbol - !ownParam.exists || ownParams.contains(ownParam.asType) - } - params.forall(isMissingOrOpen) - } - - /** Widen type by forming the intersection of its widened parents */ - def widenToParents(tp: Type) = { - val parents = tp.parents.map(p => - tp.baseTypeWithArgs(p.symbol).widenToNamedTypeParams(params)) - parents.reduceLeft(ctx.typeComparer.andType(_, _)) - } - - if (isOK(self)) self - else self match { - case self @ AppliedType(tycon, args) if !isOK(tycon) => - widenToParents(self) - case self: TypeRef if self.symbol.isClass => - widenToParents(self) - case self: RefinedType => - val parent1 = self.parent.widenToNamedTypeParams(params) - if (params.exists(_.name == self.refinedName)) parent1 - else self.derivedRefinedType(parent1, self.refinedName, self.refinedInfo) - case self: TypeProxy => - self.superType.widenToNamedTypeParams(params) - case self: AndOrType => - self.derivedAndOrType( - self.tp1.widenToNamedTypeParams(params), self.tp2.widenToNamedTypeParams(params)) - } - } - /** Is self type higher-kinded (i.e. of kind != "*")? */ def isHK(implicit ctx: Context): Boolean = self.dealias match { case self: TypeRef => self.info.isHK diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index fca111702..21a12dbb7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -484,11 +484,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => } either(isSubType(tp1, tp21), isSubType(tp1, tp22)) || fourthTry(tp1, tp2) - case tp2 @ MethodType(_, formals2) => + case tp2: MethodType => def compareMethod = tp1 match { - case tp1 @ MethodType(_, formals1) => + case tp1: MethodType => (tp1.signature consistentParams tp2.signature) && - matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && (tp1.isImplicit == tp2.isImplicit) && isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) case _ => @@ -503,7 +503,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // as members of the same type. And it seems most logical to take // ()T <:< => T, since everything one can do with a => T one can // also do with a ()T by automatic () insertion. - case tp1 @ MethodType(Nil, _) => isSubType(tp1.resultType, restpe2) + case tp1 @ MethodType(Nil) => isSubType(tp1.resultType, restpe2) case _ => isSubType(tp1.widenExpr, restpe2) } compareExpr @@ -1264,22 +1264,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } } - /** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors with at least - * some unnamed type parameters. + /** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors. * In the latter case, combine `tp1` and `tp2` under a type lambda like this: * * [X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn]) - * - * Note: There is a tension between named and positional parameters here, which - * is impossible to resolve completely. Say you have - * - * C[type T], D[type U] - * - * Then do you expand `C & D` to `[T] -> C[T] & D[T]` or not? Under the named - * type parameter interpretation, this would be wrong whereas under the traditional - * higher-kinded interpretation this would be required. The problem arises from - * allowing both interpretations. A possible remedy is to be somehow stricter - * in where we allow which interpretation. */ private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type, original: (Type, Type) => Type) = { val tparams1 = tp1.typeParams @@ -1312,23 +1300,28 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1: RefinedType => tp2 match { case tp2: RefinedType if tp1.refinedName == tp2.refinedName => - // Given two refinements `T1 { X = S1 }` and `T2 { X = S2 }`, if `S1 =:= S2` - // (possibly by instantiating type parameters), rewrite to `T1 & T2 { X = S1 }`. - // Otherwise rewrite to `T1 & T2 { X B }` where `B` is the conjunction of - // the bounds of `X` in `T1` and `T2`. - // The first rule above is contentious because it cuts the constraint set. - // But without it we would replace the two aliases by - // `T { X >: S1 | S2 <: S1 & S2 }`, which looks weird and is probably - // not what's intended. + // Given two refinements `T1 { X = S1 }` and `T2 { X = S2 }` rewrite to + // `T1 & T2 { X B }` where `B` is the conjunction of the bounds of `X` in `T1` and `T2`. + // + // However, if `homogenizeArgs` is set, and both aliases `X = Si` are + // nonvariant, and `S1 =:= S2` (possibly by instantiating type parameters), + // rewrite instead to `T1 & T2 { X = S1 }`. This rule is contentious because + // it cuts the constraint set. On the other hand, without it we would replace + // the two aliases by `T { X >: S1 | S2 <: S1 & S2 }`, which looks weird + // and is probably not what's intended. val rinfo1 = tp1.refinedInfo val rinfo2 = tp2.refinedInfo val parent = tp1.parent & tp2.parent - val rinfo = - if (rinfo1.isAlias && rinfo2.isAlias && isSameType(rinfo1, rinfo2)) - rinfo1 - else - rinfo1 & rinfo2 - tp1.derivedRefinedType(parent, tp1.refinedName, rinfo) + + def isNonvariantAlias(tp: Type) = tp match { + case tp: TypeAlias => tp.variance == 0 + case _ => false + } + if (homogenizeArgs && + isNonvariantAlias(rinfo1) && isNonvariantAlias(rinfo2)) + isSameType(rinfo1, rinfo2) // establish new constraint + + tp1.derivedRefinedType(parent, tp1.refinedName, rinfo1 & rinfo2) case _ => NoType } diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index fc18808a3..fe3396fcb 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -216,13 +216,13 @@ object TypeErasure { } /** The erased least upper bound is computed as follows - * - if both argument are arrays of objects, an array of the lub of the element types + * - if both argument are arrays of objects, an array of the erased lub of the element types * - if both arguments are arrays of same primitives, an array of this primitive * - if one argument is array of primitives and the other is array of objects, Object * - if one argument is an array, Object * - otherwise a common superclass or trait S of the argument classes, with the * following two properties: - * S is minimal: no other common superclass or trait derives from S] + * S is minimal: no other common superclass or trait derives from S * S is last : in the linearization of the first argument type `tp1` * there are no minimal common superclasses or traits that * come after S. @@ -247,10 +247,14 @@ object TypeErasure { val cls2 = tp2.classSymbol @tailrec def loop(bcs: List[ClassSymbol], bestSoFar: ClassSymbol): ClassSymbol = bcs match { case bc :: bcs1 => - if (cls2.derivesFrom(bc)) - if (!bc.is(Trait) && bc != defn.AnyClass) bc - else loop(bcs1, if (bestSoFar.derivesFrom(bc)) bestSoFar else bc) - else + if (cls2.derivesFrom(bc)) { + val newBest = if (bestSoFar.derivesFrom(bc)) bestSoFar else bc + + if (!bc.is(Trait) && bc != defn.AnyClass) + newBest + else + loop(bcs1, newBest) + } else loop(bcs1, bestSoFar) case nil => bestSoFar diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 308e6e306..6c40794e3 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -428,16 +428,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object. case tp: TypeRef => tp case tp @ RefinedType(tp1, name: TypeName, rinfo) => - rinfo match { - case TypeAlias(TypeRef(pre, name1)) if name1 == name && (pre =:= cls.thisType) => - // Don't record refinements of the form X = this.X (These can arise using named parameters). - typr.println(s"dropping refinement $tp") - case _ => - val prevInfo = refinements(name) - refinements = refinements.updated(name, - if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo) - formals = formals.updated(name, tp1.typeParamNamed(name)) - } + val prevInfo = refinements(name) + refinements = refinements.updated(name, + if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo) + formals = formals.updated(name, tp1.typeParamNamed(name)) normalizeToRef(tp1) case _: ErrorType => defn.AnyType diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6ff896110..8e852a9a9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -19,6 +19,7 @@ import util.Positions.{Position, NoPosition} import util.Stats._ import util.{DotClass, SimpleMap} import reporting.diagnostic.Message +import reporting.diagnostic.messages.CyclicReferenceInvolving import ast.tpd._ import ast.TreeTypeMap import printing.Texts._ @@ -216,14 +217,14 @@ object Types { */ def isVarArgsMethod(implicit ctx: Context): Boolean = this match { case tp: PolyType => tp.resultType.isVarArgsMethod - case MethodType(_, paramTypes) => paramTypes.nonEmpty && paramTypes.last.isRepeatedParam + case mt: MethodType => mt.paramTypes.nonEmpty && mt.paramTypes.last.isRepeatedParam case _ => false } /** Is this the type of a method with a leading empty parameter list? */ def isNullaryMethod(implicit ctx: Context): Boolean = this match { - case MethodType(Nil, _) => true + case MethodType(Nil) => true case tp: PolyType => tp.resultType.isNullaryMethod case _ => false } @@ -549,13 +550,7 @@ object Types { def goThis(tp: ThisType) = { val d = go(tp.underlying) - if (d.exists) - if ((pre eq tp) && d.symbol.is(NamedTypeParam) && (d.symbol.owner eq tp.cls)) - // If we look for a named type parameter `P` in `C.this.P`, looking up - // the fully applied self type of `C` will give as an info the alias type - // `P = this.P`. We need to return a denotation with the underlying bounds instead. - d.symbol.denot - else d + if (d.exists) d else // There is a special case to handle: // trait Super { this: Sub => private class Inner {} println(this.Inner) } @@ -737,7 +732,7 @@ object Types { */ final def overrides(that: Type)(implicit ctx: Context) = { def result(tp: Type): Type = tp match { - case ExprType(_) | MethodType(Nil, _) => tp.resultType + case ExprType(_) | MethodType(Nil) => tp.resultType case _ => tp } (this frozen_<:< that) || { @@ -1223,8 +1218,8 @@ object Types { * when forming the function type. */ def toFunctionType(dropLast: Int = 0)(implicit ctx: Context): Type = this match { - case mt @ MethodType(_, formals) if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) => - val formals1 = if (dropLast == 0) formals else formals dropRight dropLast + case mt: MethodType if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) => + val formals1 = if (dropLast == 0) mt.paramTypes else mt.paramTypes dropRight dropLast defn.FunctionOf( formals1 mapConserve (_.underlyingIfRepeated(mt.isJava)), mt.resultType, mt.isImplicit && !ctx.erasedTypes) } @@ -1279,10 +1274,14 @@ object Types { def underlying(implicit ctx: Context): Type /** The closest supertype of this type. This is the same as `underlying`, - * except for TypeRefs where the upper bound is returned, and HKApplys, - * where the upper bound of the constructor is re-applied to the arguments. + * except that + * - instead of a TyperBounds type it returns its upper bound, and + * - for HKApplys it returns the upper bound of the constructor re-applied to the arguments. */ - def superType(implicit ctx: Context): Type = underlying + def superType(implicit ctx: Context): Type = underlying match { + case TypeBounds(_, hi) => hi + case st => st + } } // Every type has to inherit one of the following four abstract type classes., @@ -1686,7 +1685,10 @@ object Types { } else newLikeThis(prefix) } - else newLikeThis(prefix) + else prefix match { + case _: WildcardType => WildcardType + case _ => newLikeThis(prefix) + } /** Create a NamedType of the same kind as this type, but with a new prefix. */ @@ -1768,11 +1770,6 @@ object Types { type ThisType = TypeRef override def underlying(implicit ctx: Context): Type = info - - override def superType(implicit ctx: Context): Type = info match { - case TypeBounds(_, hi) => hi - case _ => info - } } final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name) { @@ -2066,6 +2063,9 @@ object Types { */ abstract case class RefinedType(parent: Type, refinedName: Name, refinedInfo: Type) extends RefinedOrRecType { + if (refinedName.isTermName) assert(refinedInfo.isInstanceOf[TermType]) + else assert(refinedInfo.isInstanceOf[TypeType]) + override def underlying(implicit ctx: Context) = parent private def badInst = @@ -2312,14 +2312,16 @@ object Types { trait MethodOrPoly extends MethodicType - abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type]) - (resultTypeExp: MethodType => Type) + abstract case class MethodType(paramNames: List[TermName])( + paramTypesExp: MethodType => List[Type], + resultTypeExp: MethodType => Type) extends CachedGroundType with BindingType with TermType with MethodOrPoly with NarrowCached { thisMethodType => import MethodType._ def isJava = false def isImplicit = false + val paramTypes = paramTypesExp(this) private[core] val resType = resultTypeExp(this) assert(resType.exists) @@ -2329,7 +2331,7 @@ object Types { def apply(tp: Type) = tp match { case tp @ TypeRef(pre, name) => tp.info match { - case TypeAlias(alias) if depStatus(pre) == TrueDeps => apply(alias) + case TypeAlias(alias) if depStatus(NoDeps, pre) == TrueDeps => apply(alias) case _ => mapOver(tp) } case _ => @@ -2341,8 +2343,9 @@ object Types { else resType var myDependencyStatus: DependencyStatus = Unknown + var myParamDependencyStatus: DependencyStatus = Unknown - private def depStatus(tp: Type)(implicit ctx: Context): DependencyStatus = { + private def depStatus(initial: DependencyStatus, tp: Type)(implicit ctx: Context): DependencyStatus = { def combine(x: DependencyStatus, y: DependencyStatus) = { val status = (x & StatusMask) max (y & StatusMask) val provisional = (x | y) & Provisional @@ -2366,7 +2369,7 @@ object Types { case _ => foldOver(status, tp) } } - depStatusAcc(NoDeps, tp) + depStatusAcc(initial, tp) } /** The dependency status of this method. Some examples: @@ -2380,17 +2383,36 @@ object Types { private def dependencyStatus(implicit ctx: Context): DependencyStatus = { if (myDependencyStatus != Unknown) myDependencyStatus else { - val result = depStatus(resType) + val result = depStatus(NoDeps, resType) if ((result & Provisional) == 0) myDependencyStatus = result (result & StatusMask).toByte } } + /** The parameter dependency status of this method. Analogous to `dependencyStatus`, + * but tracking dependencies in same parameter list. + */ + private def paramDependencyStatus(implicit ctx: Context): DependencyStatus = { + if (myParamDependencyStatus != Unknown) myParamDependencyStatus + else { + val result = + if (paramTypes.isEmpty) NoDeps + else (NoDeps /: paramTypes.tail)(depStatus(_, _)) + if ((result & Provisional) == 0) myParamDependencyStatus = result + (result & StatusMask).toByte + } + } + /** Does result type contain references to parameters of this method type, * which cannot be eliminated by de-aliasing? */ def isDependent(implicit ctx: Context): Boolean = dependencyStatus == TrueDeps + /** Does one of the parameter types contain references to earlier parameters + * of this method type which cannot be eliminated by de-aliasing? + */ + def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps + protected def computeSignature(implicit ctx: Context): Signature = resultSignature.prepend(paramTypes, isJava) @@ -2399,10 +2421,11 @@ object Types { resType: Type = this.resType)(implicit ctx: Context) = if ((paramNames eq this.paramNames) && (paramTypes eq this.paramTypes) && (resType eq this.resType)) this else { + val paramTypesFn = (x: MethodType) => paramTypes.map(_.subst(this, x)) val resTypeFn = (x: MethodType) => resType.subst(this, x) - if (isJava) JavaMethodType(paramNames, paramTypes)(resTypeFn) - else if (isImplicit) ImplicitMethodType(paramNames, paramTypes)(resTypeFn) - else MethodType(paramNames, paramTypes)(resTypeFn) + if (isJava) JavaMethodType(paramNames)(paramTypesFn, resTypeFn) + else if (isImplicit) ImplicitMethodType(paramNames)(paramTypesFn, resTypeFn) + else MethodType(paramNames)(paramTypesFn, resTypeFn) } def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type = @@ -2424,21 +2447,21 @@ object Types { override def toString = s"$prefixString($paramNames, $paramTypes, $resType)" } - final class CachedMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) - extends MethodType(paramNames, paramTypes)(resultTypeExp) { + final class CachedMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type) + extends MethodType(paramNames)(paramTypesExp, resultTypeExp) { override def equals(that: Any) = super.equals(that) && that.isInstanceOf[CachedMethodType] } - final class JavaMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) - extends MethodType(paramNames, paramTypes)(resultTypeExp) { + final class JavaMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type) + extends MethodType(paramNames)(paramTypesExp, resultTypeExp) { override def isJava = true override def equals(that: Any) = super.equals(that) && that.isInstanceOf[JavaMethodType] override def computeHash = addDelta(super.computeHash, 1) override protected def prefixString = "JavaMethodType" } - final class ImplicitMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) - extends MethodType(paramNames, paramTypes)(resultTypeExp) { + final class ImplicitMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type) + extends MethodType(paramNames)(paramTypesExp, resultTypeExp) { override def isImplicit = true override def equals(that: Any) = super.equals(that) && that.isInstanceOf[ImplicitMethodType] override def computeHash = addDelta(super.computeHash, 2) @@ -2446,11 +2469,11 @@ object Types { } abstract class MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType def apply(paramNames: List[TermName], paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = - apply(paramNames, paramTypes)(_ => resultType) + apply(paramNames)(_ => paramTypes, _ => resultType) def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = - apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp) + apply(nme.syntheticParamNames(paramTypes.length))(_ => paramTypes, resultTypeExp) def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) @@ -2473,19 +2496,31 @@ object Types { case _: ExprType => tp case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot)) } + def integrate(tp: Type, mt: MethodType) = + tp.subst(params, (0 until params.length).toList.map(MethodParam(mt, _))) def paramInfo(param: Symbol): Type = { val paramType = translateRepeated(param.info) if (param.is(Inline)) translateInline(paramType) else paramType } - def transformResult(mt: MethodType) = - resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _))) - apply(params map (_.name.asTermName), params map paramInfo)(transformResult _) + apply(params.map(_.name.asTermName))( + mt => params.map(param => integrate(paramInfo(param), mt)), + mt => integrate(resultType, mt)) + } + + def checkValid(mt: MethodType)(implicit ctx: Context): mt.type = { + if (Config.checkMethodTypes) + for ((paramType, idx) <- mt.paramTypes.zipWithIndex) + paramType.foreachPart { + case MethodParam(`mt`, j) => assert(j < idx, mt) + case _ => + } + mt } } object MethodType extends MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) = - unique(new CachedMethodType(paramNames, paramTypes)(resultTypeExp)) + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + checkValid(unique(new CachedMethodType(paramNames)(paramTypesExp, resultTypeExp))) private type DependencyStatus = Byte private final val Unknown: DependencyStatus = 0 // not yet computed @@ -2497,13 +2532,19 @@ object Types { } object JavaMethodType extends MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) = - unique(new JavaMethodType(paramNames, paramTypes)(resultTypeExp)) + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + unique(new JavaMethodType(paramNames)(paramTypesExp, resultTypeExp)) } object ImplicitMethodType extends MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) = - unique(new ImplicitMethodType(paramNames, paramTypes)(resultTypeExp)) + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + checkValid(unique(new ImplicitMethodType(paramNames)(paramTypesExp, resultTypeExp))) + } + + /** A ternary extractor for MethodType */ + object MethodTpe { + def unapply(mt: MethodType)(implicit ctx: Context) = + Some((mt.paramNames, mt.paramTypes, mt.resultType)) } /** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */ @@ -2547,11 +2588,6 @@ object Types { case _ => false } - /** Is this polytype a higher-kinded type lambda as opposed to a polymorphic? - * method type? Only type lambdas get created with variances, that's how we can tell. - */ - def isTypeLambda: Boolean = variances.nonEmpty - /** PolyParam references to all type parameters of this type */ lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _)) @@ -2928,20 +2964,8 @@ object Types { * instantiation can be a singleton type only if the upper bound * is also a singleton type. */ - def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = { - val inst = ctx.typeComparer.instanceType(origin, fromBelow) - if (ctx.typerState.isGlobalCommittable) - inst match { - case inst: PolyParam => - assert(inst.binder.isTypeLambda, i"bad inst $this := $inst, constr = ${ctx.typerState.constraint}") - // If this fails, you might want to turn on Config.debugCheckConstraintsClosed - // to help find the root of the problem. - // Note: Parameters of type lambdas are excluded from the assertion because - // they might arise from ill-kinded code. See #1652 - case _ => - } - instantiateWith(inst) - } + def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = + instantiateWith(ctx.typeComparer.instanceType(origin, fromBelow)) /** Unwrap to instance (if instantiated) or origin (if not), until result * is no longer a TypeVar @@ -3328,6 +3352,8 @@ object Types { zeroParamClass(tp.underlying) case tp: TypeVar => zeroParamClass(tp.underlying) + case tp: HKApply => + zeroParamClass(tp.superType) case _ => NoType } @@ -3546,6 +3572,13 @@ object Types { def apply(tp: Type) = tp } + /** A type map that approximates NoTypes by upper or lower known bounds depending on + * variance. + * + * if variance > 0 : approximate by upper bound + * variance < 0 : approximate by lower bound + * variance = 0 : propagate NoType to next outer level + */ abstract class ApproximatingTypeMap(implicit ctx: Context) extends TypeMap { thisMap => def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType) = if (variance == 0) NoType @@ -3651,9 +3684,9 @@ object Types { this(y, hi) } - case tp @ MethodType(pnames, ptypes) => + case tp: MethodType => variance = -variance - val y = foldOver(x, ptypes) + val y = foldOver(x, tp.paramTypes) variance = -variance this(y, tp.resultType) @@ -3856,7 +3889,7 @@ object Types { class CyclicReference private (val denot: SymDenotation) extends TypeError(s"cyclic reference involving $denot") { - def show(implicit ctx: Context) = s"cyclic reference involving ${denot.show}" + def toMessage(implicit ctx: Context) = CyclicReferenceInvolving(denot) } object CyclicReference { diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 36d478c6d..bc140c26b 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -198,8 +198,8 @@ class ClassfileParser( */ def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match { case Some(entry) if !isStatic(entry.jflags) => - val mt @ MethodType(paramnames, paramtypes) = denot.info - denot.info = mt.derivedMethodType(paramnames.tail, paramtypes.tail, mt.resultType) + val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info + denot.info = mt.derivedMethodType(paramNames.tail, paramTypes.tail, resultType) case _ => } @@ -207,9 +207,9 @@ class ClassfileParser( * and make constructor type polymorphic in the type parameters of the class */ def normalizeConstructorInfo() = { - val mt @ MethodType(paramnames, paramtypes) = denot.info + val mt @ MethodType(paramNames) = denot.info val rt = classRoot.typeRef appliedTo (classRoot.typeParams map (_.typeRef)) - denot.info = mt.derivedMethodType(paramnames, paramtypes, rt) + denot.info = mt.derivedMethodType(paramNames, mt.paramTypes, rt) addConstructorTypeParams(denot) } @@ -339,7 +339,7 @@ class ClassfileParser( } index += 1 val restype = sig2type(tparams, skiptvs) - JavaMethodType(paramnames.toList, paramtypes.toList)(_ => restype) + JavaMethodType(paramnames.toList, paramtypes.toList, restype) case 'T' => val n = subName(';'.==).toTypeName index += 1 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index fcba957c0..a9ea49ad1 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -278,8 +278,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle result case METHODtype => val (names, paramReader) = readNamesSkipParams - val result = MethodType(names.map(_.toTermName), paramReader.readParamTypes[Type](end))( - mt => registeringType(mt, readType())) + val result = MethodType(names.map(_.toTermName))( + mt => registeringType(mt, paramReader.readParamTypes[Type](end)), + mt => readType()) goto(end) result case PARAMtype => @@ -768,7 +769,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle } else EmptyValDef setClsInfo(parentRefs, if (self.isEmpty) NoType else self.tpt.tpe) - cls.setApplicableFlags(fork.indexStats(end)) + cls.setNoInitsFlags(fork.indexStats(end)) val constr = readIndexedDef().asInstanceOf[DefDef] def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) = diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index 17fef3852..6ee9f1f9e 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -193,24 +193,7 @@ object PickleBuffer { private type FlagMap = Array[Array[Long]] private val (scalaTermFlagMap, scalaTypeFlagMap) = { - import scala.reflect.internal.Flags._ - - // The following vals are copy-pasted from reflect.internal.Flags. - // They are unfortunately private there, so we cannot get at them directly. - // Using the public method pickledToRawFlags instead looks unattractive - // because of performance. - val IMPLICIT_PKL = (1 << 0) - val FINAL_PKL = (1 << 1) - val PRIVATE_PKL = (1 << 2) - val PROTECTED_PKL = (1 << 3) - val SEALED_PKL = (1 << 4) - val OVERRIDE_PKL = (1 << 5) - val CASE_PKL = (1 << 6) - val ABSTRACT_PKL = (1 << 7) - val DEFERRED_PKL = (1 << 8) - val METHOD_PKL = (1 << 9) - val MODULE_PKL = (1 << 10) - val INTERFACE_PKL = (1 << 11) + import Scala2Flags._ val corr = Map( PROTECTED_PKL -> Protected, diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala new file mode 100644 index 000000000..a8855545f --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala @@ -0,0 +1,227 @@ +package dotty.tools +package dotc +package core +package unpickleScala2 + +/** This object provides constants for pickling attributes. + * + * If you extend the format, be sure to increase the + * version minor number. + * + * This was adapted from https://github.com/scala/scala/blob/2.11.x/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala + * + * @author Martin Odersky + * @version 1.0 + */ +object PickleFormat { + +/*************************************************** + * Symbol table attribute format: + * Symtab = nentries_Nat {Entry} + * Entry = 1 TERMNAME len_Nat NameInfo + * | 2 TYPENAME len_Nat NameInfo + * | 3 NONEsym len_Nat + * | 4 TYPEsym len_Nat SymbolInfo + * | 5 ALIASsym len_Nat SymbolInfo + * | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref] + * | 7 MODULEsym len_Nat SymbolInfo + * | 8 VALsym len_Nat [defaultGetter_Ref /* no longer needed*/] SymbolInfo [alias_Ref] + * | 9 EXTref len_Nat name_Ref [owner_Ref] + * | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref] + * | 11 NOtpe len_Nat + * | 12 NOPREFIXtpe len_Nat + * | 13 THIStpe len_Nat sym_Ref + * | 14 SINGLEtpe len_Nat type_Ref sym_Ref + * | 15 CONSTANTtpe len_Nat constant_Ref + * | 16 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref} + * | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref + * | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref} + * | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref} + * | 20 METHODtpe len_Nat tpe_Ref {sym_Ref} + * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref} + * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {sym_Ref} /* no longer needed */ + * | 52 SUPERtpe len_Nat tpe_Ref tpe_Ref + * | 24 LITERALunit len_Nat + * | 25 LITERALboolean len_Nat value_Long + * | 26 LITERALbyte len_Nat value_Long + * | 27 LITERALshort len_Nat value_Long + * | 28 LITERALchar len_Nat value_Long + * | 29 LITERALint len_Nat value_Long + * | 30 LITERALlong len_Nat value_Long + * | 31 LITERALfloat len_Nat value_Long + * | 32 LITERALdouble len_Nat value_Long + * | 33 LITERALstring len_Nat name_Ref + * | 34 LITERALnull len_Nat + * | 35 LITERALclass len_Nat tpe_Ref + * | 36 LITERALenum len_Nat sym_Ref + * | 40 SYMANNOT len_Nat sym_Ref AnnotInfoBody + * | 41 CHILDREN len_Nat sym_Ref {sym_Ref} + * | 42 ANNOTATEDtpe len_Nat [sym_Ref /* no longer needed */] tpe_Ref {annotinfo_Ref} + * | 43 ANNOTINFO len_Nat AnnotInfoBody + * | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref} + * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat /* no longer needed */ + * | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref} + * | 49 TREE len_Nat 1 EMPTYtree + * | 49 TREE len_Nat 2 PACKAGEtree type_Ref sym_Ref mods_Ref name_Ref {tree_Ref} + * | 49 TREE len_Nat 3 CLASStree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 4 MODULEtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref + * | 49 TREE len_Nat 5 VALDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 6 DEFDEFtree type_Ref sym_Ref mods_Ref name_Ref numtparams_Nat {tree_Ref} numparamss_Nat {numparams_Nat {tree_Ref}} tree_Ref tree_Ref + * | 49 TREE len_Nat 7 TYPEDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 8 LABELtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 9 IMPORTtree type_Ref sym_Ref tree_Ref {name_Ref name_Ref} + * | 49 TREE len_Nat 11 DOCDEFtree type_Ref sym_Ref string_Ref tree_Ref + * | 49 TREE len_Nat 12 TEMPLATEtree type_Ref sym_Ref numparents_Nat {tree_Ref} tree_Ref {tree_Ref} + * | 49 TREE len_Nat 13 BLOCKtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 14 CASEtree type_Ref tree_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 15 SEQUENCEtree type_Ref {tree_Ref} + * | 49 TREE len_Nat 16 ALTERNATIVEtree type_Ref {tree_Ref} + * | 49 TREE len_Nat 17 STARtree type_Ref {tree_Ref} + * | 49 TREE len_Nat 18 BINDtree type_Ref sym_Ref name_Ref tree_Ref + * | 49 TREE len_Nat 19 UNAPPLYtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 20 ARRAYVALUEtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 21 FUNCTIONtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 22 ASSIGNtree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 23 IFtree type_Ref tree_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 24 MATCHtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 25 RETURNtree type_Ref sym_Ref tree_Ref + * | 49 TREE len_Nat 26 TREtree type_Ref tree_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 27 THROWtree type_Ref tree_Ref + * | 49 TREE len_Nat 28 NEWtree type_Ref tree_Ref + * | 49 TREE len_Nat 29 TYPEDtree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 30 TYPEAPPLYtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 31 APPLYtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 32 APPLYDYNAMICtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 33 SUPERtree type_Ref sym_Ref tree_Ref name_Ref + * | 49 TREE len_Nat 34 THIStree type_Ref sym_Ref name_Ref + * | 49 TREE len_Nat 35 SELECTtree type_Ref sym_Ref tree_Ref name_Ref + * | 49 TREE len_Nat 36 IDENTtree type_Ref sym_Ref name_Ref + * | 49 TREE len_Nat 37 LITERALtree type_Ref constant_Ref + * | 49 TREE len_Nat 38 TYPEtree type_Ref + * | 49 TREE len_Nat 39 ANNOTATEDtree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 40 SINGLETONTYPEtree type_Ref tree_Ref + * | 49 TREE len_Nat 41 SELECTFROMTYPEtree type_Ref tree_Ref name_Ref + * | 49 TREE len_Nat 42 COMPOUNDTYPEtree type_Ref tree_Ref + * | 49 TREE len_Nat 43 APPLIEDTYPEtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 44 TYPEBOUNDStree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 45 EXISTENTIALTYPEtree type_Ref tree_Ref {tree_Ref} + * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref + * SymbolInfo = name_Ref owner_Ref flags_LongNat [privateWithin_Ref] info_Ref + * NameInfo = <character sequence of length len_Nat in Utf8 format> + * NumInfo = <len_Nat-byte signed number in big endian format> + * Ref = Nat + * AnnotInfoBody = info_Ref {annotArg_Ref} {name_Ref constAnnotArg_Ref} + * AnnotArg = Tree | Constant + * ConstAnnotArg = Constant | AnnotInfo | AnnotArgArray + * + * len is remaining length after `len`. + */ + val MajorVersion = 5 + val MinorVersion = 0 + + final val TERMname = 1 + final val TYPEname = 2 + final val NONEsym = 3 + final val TYPEsym = 4 + final val ALIASsym = 5 + final val CLASSsym = 6 + final val MODULEsym = 7 + final val VALsym = 8 + final val EXTref = 9 + final val EXTMODCLASSref = 10 + final val NOtpe = 11 + final val NOPREFIXtpe = 12 + final val THIStpe = 13 + final val SINGLEtpe = 14 + final val CONSTANTtpe = 15 + final val TYPEREFtpe = 16 + final val TYPEBOUNDStpe = 17 + final val REFINEDtpe = 18 + final val CLASSINFOtpe = 19 + final val METHODtpe = 20 + final val POLYtpe = 21 + final val IMPLICITMETHODtpe = 22 // no longer generated + + final val LITERAL = 23 // base line for literals + final val LITERALunit = 24 + final val LITERALboolean = 25 + final val LITERALbyte = 26 + final val LITERALshort = 27 + final val LITERALchar = 28 + final val LITERALint = 29 + final val LITERALlong = 30 + final val LITERALfloat = 31 + final val LITERALdouble = 32 + final val LITERALstring = 33 + final val LITERALnull = 34 + final val LITERALclass = 35 + final val LITERALenum = 36 + final val SYMANNOT = 40 + final val CHILDREN = 41 + final val ANNOTATEDtpe = 42 + final val ANNOTINFO = 43 + final val ANNOTARGARRAY = 44 + + final val SUPERtpe = 46 + final val DEBRUIJNINDEXtpe = 47 // no longer generated + final val EXISTENTIALtpe = 48 + + final val TREE = 49 // prefix code that means a tree is coming + final val EMPTYtree = 1 + final val PACKAGEtree = 2 + final val CLASStree = 3 + final val MODULEtree = 4 + final val VALDEFtree = 5 + final val DEFDEFtree = 6 + final val TYPEDEFtree = 7 + final val LABELtree = 8 + final val IMPORTtree = 9 + final val DOCDEFtree = 11 + final val TEMPLATEtree = 12 + final val BLOCKtree = 13 + final val CASEtree = 14 + // This node type has been removed. + // final val SEQUENCEtree = 15 + final val ALTERNATIVEtree = 16 + final val STARtree = 17 + final val BINDtree = 18 + final val UNAPPLYtree = 19 + final val ARRAYVALUEtree = 20 + final val FUNCTIONtree = 21 + final val ASSIGNtree = 22 + final val IFtree = 23 + final val MATCHtree = 24 + final val RETURNtree = 25 + final val TREtree = 26 + final val THROWtree = 27 + final val NEWtree = 28 + final val TYPEDtree = 29 + final val TYPEAPPLYtree = 30 + final val APPLYtree = 31 + final val APPLYDYNAMICtree = 32 + final val SUPERtree = 33 + final val THIStree = 34 + final val SELECTtree = 35 + final val IDENTtree = 36 + final val LITERALtree = 37 + final val TYPEtree = 38 + final val ANNOTATEDtree = 39 + final val SINGLETONTYPEtree = 40 + final val SELECTFROMTYPEtree = 41 + final val COMPOUNDTYPEtree = 42 + final val APPLIEDTYPEtree = 43 + final val TYPEBOUNDStree = 44 + final val EXISTENTIALTYPEtree = 45 + + final val MODIFIERS = 50 + + final val firstSymTag = NONEsym + final val lastSymTag = VALsym + final val lastExtSymTag = EXTMODCLASSref + + + //The following two are no longer accurate, because ANNOTATEDtpe, + //SUPERtpe, ... are not in the same range as the other types + //final val firstTypeTag = NOtpe + //final val lastTypeTag = POLYtpe +} diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala new file mode 100644 index 000000000..97480e49f --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala @@ -0,0 +1,109 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Martin Odersky + */ + +package dotty.tools +package dotc +package core +package unpickleScala2 + +import scala.collection.{ mutable, immutable } + +/** Scala2 flags, adapted from https://github.com/scala/scala/blob/2.11.x/src/reflect/scala/reflect/internal/Flags.scala + */ +object Scala2Flags { + final val IMPLICIT = 1 << 9 + final val FINAL = 1 << 5 // May not be overridden. Note that java final implies much more than scala final. + final val PRIVATE = 1 << 2 + final val PROTECTED = 1 << 0 + + final val SEALED = 1 << 10 + final val OVERRIDE = 1 << 1 + final val CASE = 1 << 11 + final val ABSTRACT = 1 << 3 // abstract class, or used in conjunction with abstract override. + // Note difference to DEFERRED! + final val DEFERRED = 1 << 4 // was `abstract' for members | trait is virtual + final val INTERFACE = 1 << 7 // symbol is an interface (i.e. a trait which defines only abstract methods) + final val MUTABLE = 1 << 12 // symbol is a mutable variable. + final val PARAM = 1 << 13 // symbol is a (value or type) parameter to a method + final val MACRO = 1 << 15 // symbol is a macro definition + + final val COVARIANT = 1 << 16 // symbol is a covariant type variable + final val BYNAMEPARAM = 1 << 16 // parameter is by name + final val CONTRAVARIANT = 1 << 17 // symbol is a contravariant type variable + final val ABSOVERRIDE = 1 << 18 // combination of abstract & override + final val LOCAL = 1 << 19 // symbol is local to current class (i.e. private[this] or protected[this] + // pre: PRIVATE or PROTECTED are also set + final val JAVA = 1 << 20 // symbol was defined by a Java class + final val STATIC = 1 << 23 // static field, method or class + final val CASEACCESSOR = 1 << 24 // symbol is a case parameter (or its accessor, or a GADT skolem) + final val TRAIT = 1 << 25 // symbol is a trait + final val DEFAULTPARAM = 1 << 25 // the parameter has a default value + final val PARAMACCESSOR = 1 << 29 // for field definitions generated for primary constructor + // parameters (no matter if it's a 'val' parameter or not) + // for parameters of a primary constructor ('val' or not) + // for the accessor methods generated for 'val' or 'var' parameters + final val LAZY = 1L << 31 // symbol is a lazy val. can't have MUTABLE unless transformed by typer + final val PRESUPER = 1L << 37 // value is evaluated before super call + final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit + final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode + // to see which symbols are marked as ARTIFACT, see scaladocs for FlagValues.ARTIFACT + final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method + final val ENUM = 1L << 48 // symbol is an enum + + final val PrivateLocal = PRIVATE | LOCAL + final val ProtectedLocal = PROTECTED | LOCAL + final val AccessFlags = PRIVATE | PROTECTED | LOCAL + + final val METHOD = 1 << 6 // a method + final val MODULE = 1 << 8 // symbol is module or class implementing a module + final val PACKAGE = 1 << 14 // symbol is a java package + + final val CAPTURED = 1 << 16 // variable is accessed from nested function. Set by LambdaLift. + final val LABEL = 1 << 17 // method symbol is a label. Set by TailCall + final val INCONSTRUCTOR = 1 << 17 // class symbol is defined in this/superclass constructor. + final val SYNTHETIC = 1 << 21 // symbol is compiler-generated (compare with ARTIFACT) + final val STABLE = 1 << 22 // functions that are assumed to be stable + // (typically, access methods for valdefs) + // or classes that do not contain abstract types. + final val BRIDGE = 1 << 26 // function is a bridge method. Set by Erasure + final val ACCESSOR = 1 << 27 // a value or variable accessor (getter or setter) + + final val SUPERACCESSOR = 1 << 28 // a super accessor + final val MODULEVAR = 1 << 30 // for variables: is the variable caching a module value + + final val IS_ERROR = 1L << 32 // symbol is an error symbol + final val OVERLOADED = 1L << 33 // symbol is overloaded + final val LIFTED = 1L << 34 // class has been lifted out to package level + // local value has been lifted out to class level + // todo: make LIFTED = latePRIVATE? + final val MIXEDIN = 1L << 35 // term member has been mixed in + final val EXISTENTIAL = 1L << 35 // type is an existential parameter or skolem + final val EXPANDEDNAME = 1L << 36 // name has been expanded with class suffix + final val IMPLCLASS = 1L << 37 // symbol is an implementation class + final val TRANS_FLAG = 1L << 38 // transient flag guaranteed to be reset after each phase. + + final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies + final val SPECIALIZED = 1L << 40 // symbol is a generated specialized member + final val VBRIDGE = 1L << 42 // symbol is a varargs bridge + + final val VARARGS = 1L << 43 // symbol is a Java-style varargs method + final val TRIEDCOOKING = 1L << 44 // `Cooking` has been tried on this symbol + // A Java method's type is `cooked` by transforming raw types to existentials + + final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED + + final val IMPLICIT_PKL = (1 << 0) + final val FINAL_PKL = (1 << 1) + final val PRIVATE_PKL = (1 << 2) + final val PROTECTED_PKL = (1 << 3) + final val SEALED_PKL = (1 << 4) + final val OVERRIDE_PKL = (1 << 5) + final val CASE_PKL = (1 << 6) + final val ABSTRACT_PKL = (1 << 7) + final val DEFERRED_PKL = (1 << 8) + final val METHOD_PKL = (1 << 9) + final val MODULE_PKL = (1 << 10) + final val INTERFACE_PKL = (1 << 11) +} diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 3a2a45fd2..688a2d007 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -19,7 +19,7 @@ import io.AbstractFile import util.common._ import typer.Checking.checkNonCyclic import PickleBuffer._ -import scala.reflect.internal.pickling.PickleFormat._ +import PickleFormat._ import Decorators._ import TypeApplications._ import classfile.ClassfileParser @@ -55,8 +55,8 @@ object Scala2Unpickler { * to `RepeatedParamClass` types. */ def arrayToRepeated(tp: Type)(implicit ctx: Context): Type = tp match { - case tp @ MethodType(paramNames, paramTypes) => - val lastArg = paramTypes.last + case tp: MethodType => + val lastArg = tp.paramTypes.last assert(lastArg isRef defn.ArrayClass) val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass) val elemtp = elemtp0 match { @@ -66,8 +66,8 @@ object Scala2Unpickler { elemtp0 } tp.derivedMethodType( - paramNames, - paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp), + tp.paramNames, + tp.paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp), tp.resultType) case tp: PolyType => tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType)) diff --git a/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala b/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala index b84e2eb47..e20eb392d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala +++ b/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala @@ -2,7 +2,7 @@ package dotty.tools package dotc package parsing -import scala.reflect.internal.Chars._ +import util.Chars._ abstract class CharArrayReader { self => diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index d35594823..6b73a9456 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -26,7 +26,6 @@ import dotty.tools.dotc.util.SourceFile import util.Positions._ import annotation.switch import scala.collection.mutable.ListBuffer -import scala.reflect.internal.util.Collections._ object JavaParsers { @@ -136,7 +135,7 @@ object JavaParsers { ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.ParamAccessor)) def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined) = { - val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p)) + val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p) } DefDef(nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree).withMods(Modifiers(flags)) } diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala b/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala index 83e16627c..9e0da2c05 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala @@ -7,7 +7,7 @@ import Scanners._ import util.SourceFile import JavaTokens._ import scala.annotation.{ switch, tailrec } -import scala.reflect.internal.Chars._ +import util.Chars._ object JavaScanners { diff --git a/compiler/src/dotty/tools/dotc/parsing/MarkupParserCommon.scala b/compiler/src/dotty/tools/dotc/parsing/MarkupParserCommon.scala index ce2c41797..492a8947c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/MarkupParserCommon.scala +++ b/compiler/src/dotty/tools/dotc/parsing/MarkupParserCommon.scala @@ -9,7 +9,7 @@ package dotty.tools.dotc package parsing import Utility._ -import scala.reflect.internal.Chars.SU +import util.Chars.SU diff --git a/compiler/src/dotty/tools/dotc/parsing/MarkupParsers.scala b/compiler/src/dotty/tools/dotc/parsing/MarkupParsers.scala index f648b9e2c..3b091d542 100644 --- a/compiler/src/dotty/tools/dotc/parsing/MarkupParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/MarkupParsers.scala @@ -5,7 +5,7 @@ package parsing import scala.collection.mutable import mutable.{ Buffer, ArrayBuffer, ListBuffer } import scala.util.control.ControlThrowable -import scala.reflect.internal.Chars.SU +import util.Chars.SU import Parsers._ import util.Positions._ import core._ diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index b27bff37a..65c7a290d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -805,7 +805,7 @@ object Parsers { private def simpleTypeRest(t: Tree): Tree = in.token match { case HASH => simpleTypeRest(typeProjection(t)) case LBRACKET => simpleTypeRest(atPos(startOffset(t)) { - AppliedTypeTree(t, typeArgs(namedOK = true, wildOK = true)) }) + AppliedTypeTree(t, typeArgs(namedOK = false, wildOK = true)) }) case _ => t } @@ -1664,7 +1664,7 @@ object Parsers { /* -------- PARAMETERS ------------------------------------------- */ /** ClsTypeParamClause::= `[' ClsTypeParam {`,' ClsTypeParam} `]' - * ClsTypeParam ::= {Annotation} [{Modifier} type] [`+' | `-'] + * ClsTypeParam ::= {Annotation} [`+' | `-'] * id [HkTypeParamClause] TypeParamBounds * * DefTypeParamClause::= `[' DefTypeParam {`,' DefTypeParam} `]' @@ -1680,25 +1680,17 @@ object Parsers { def typeParam(): TypeDef = { val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def val start = in.offset - var mods = annotsAsMods() - if (ownerKind == ParamOwner.Class) { - mods = modifiers(start = mods) - mods = - atPos(start, in.offset) { - if (in.token == TYPE) { - val mod = atPos(in.skipToken()) { Mod.Type() } - (mods | Param | ParamAccessor).withAddedMod(mod) - } else { - if (mods.hasFlags) syntaxError(TypeParamsTypeExpected(mods, ident())) - mods | Param | PrivateLocal - } - } - } - else mods = atPos(start) (mods | Param) - if (ownerKind != ParamOwner.Def) { - if (isIdent(nme.raw.PLUS)) mods |= Covariant - else if (isIdent(nme.raw.MINUS)) mods |= Contravariant - if (mods is VarianceFlags) in.nextToken() + val mods = atPos(start) { + annotsAsMods() | { + if (ownerKind == ParamOwner.Class) Param | PrivateLocal + else Param + } | { + if (ownerKind != ParamOwner.Def) + if (isIdent(nme.raw.PLUS)) { in.nextToken(); Covariant } + else if (isIdent(nme.raw.MINUS)) { in.nextToken(); Contravariant } + else EmptyFlags + else EmptyFlags + } } atPos(start, nameStart) { val name = diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index b75169792..847f600c0 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -6,7 +6,7 @@ import core.Names._, core.Contexts._, core.Decorators._, util.Positions._ import core.StdNames._, core.Comments._ import util.SourceFile import java.lang.Character.isDigit -import scala.reflect.internal.Chars._ +import util.Chars._ import Tokens._ import scala.annotation.{ switch, tailrec } import scala.collection.mutable diff --git a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala index 09d1b20b1..c99826488 100644 --- a/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala +++ b/compiler/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala @@ -5,12 +5,12 @@ package parsing import scala.collection.mutable import scala.xml.{ EntityRef, Text } import core._ +import Decorators._ import Flags.Mutable import Names._, StdNames._, ast.Trees._, ast.{tpd, untpd} import Symbols._, Contexts._ import util.Positions._ import Parsers.Parser -import scala.reflect.internal.util.StringOps.splitWhere import scala.language.implicitConversions /** This class builds instance of `Tree` that represent XML. @@ -171,7 +171,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(implicit ctx: Cont } /** Returns (Some(prefix) | None, rest) based on position of ':' */ - def splitPrefix(name: String): (Option[String], String) = splitWhere(name, _ == ':', true) match { + def splitPrefix(name: String): (Option[String], String) = name.splitWhere(_ == ':', doDropIndex = true) match { case Some((pre, rest)) => (Some(pre), rest) case _ => (None, name) } diff --git a/compiler/src/dotty/tools/dotc/parsing/Utility.scala b/compiler/src/dotty/tools/dotc/parsing/Utility.scala index f522492f8..8af594d68 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Utility.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Utility.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc.parsing +package dotty.tools.dotc +package parsing import scala.collection.mutable @@ -10,7 +11,7 @@ import scala.collection.mutable * @author Burak Emir */ object Utility { - import scala.reflect.internal.Chars.SU + import util.Chars.SU private val unescMap = Map( "lt" -> '<', diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 0d1068b8c..67d44daa1 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -4,6 +4,7 @@ package printing import core._ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, Denotations._ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation +import TypeApplications.AppliedType import StdNames.{nme, tpnme} import ast.Trees._, ast._ import typer.Implicits._ @@ -119,10 +120,11 @@ class PlainPrinter(_ctx: Context) extends Printer { } /** The longest sequence of refinement types, starting at given type - * and following parents. + * and following parents, but stopping at applied types. */ private def refinementChain(tp: Type): List[Type] = tp :: (tp match { + case AppliedType(_, _) => Nil case tp: RefinedType => refinementChain(tp.parent.stripTypeVar) case _ => Nil }) @@ -481,7 +483,7 @@ class PlainPrinter(_ctx: Context) extends Printer { else Text() - nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ node.pos.toString + nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ (node.pos.toString provided ctx.settings.Yprintpos.value) case _ => tree.fallbackToText(this) } diff --git a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala index 86f34e64d..e20f846ac 100644 --- a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala +++ b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala @@ -6,6 +6,7 @@ import parsing.Tokens._ import scala.annotation.switch import scala.collection.mutable.StringBuilder import core.Contexts.Context +import util.Chars.{ LF, FF, CR, SU } import Highlighting.{Highlight, HighlightBuffer} /** This object provides functions for syntax highlighting in the REPL */ @@ -26,7 +27,7 @@ object SyntaxHighlighting { private def valDef(str: String) = ValDefColor + str + NoColor private def operator(str: String) = TypeColor + str + NoColor private def annotation(str: String) = - if (str.trim == "@") str else AnnotationColor + str + NoColor + if (str.trim == "@") str else { AnnotationColor + str + NoColor } private val tripleQs = Console.RED_B + "???" + NoColor private val keywords: Seq[String] = for { @@ -152,7 +153,11 @@ object SyntaxHighlighting { var open = 1 while (open > 0 && remaining.nonEmpty) { curr = takeChar() - newBuf += curr + if (curr == '@') { + appendWhile('@', !typeEnders.contains(_), annotation) + newBuf append CommentColor + } + else newBuf += curr if (curr == '*' && remaining.nonEmpty) { curr = takeChar() @@ -163,6 +168,11 @@ object SyntaxHighlighting { newBuf += curr if (curr == '*') open += 1 } + + (curr: @switch) match { + case LF | FF | CR | SU => newBuf append CommentColor + case _ => () + } } prev = curr newBuf append NoColor @@ -236,6 +246,11 @@ object SyntaxHighlighting { newBuf += curr closing = 0 } + + (curr: @switch) match { + case LF | FF | CR | SU => newBuf append LiteralColor + case _ => () + } } newBuf append NoColor prev = curr diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 190445d60..17eb8d39b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -5,9 +5,12 @@ package reporting import core.Contexts.Context import core.Decorators._ import printing.Highlighting.{Blue, Red} +import printing.SyntaxHighlighting import diagnostic.{ErrorMessageID, Message, MessageContainer, NoExplanation} import diagnostic.messages._ import util.SourcePosition +import util.Chars.{ LF, CR, FF, SU } +import scala.annotation.switch import scala.collection.mutable @@ -38,20 +41,37 @@ trait MessageRendering { */ def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { var maxLen = Int.MinValue - def render(xs: List[Int]) = - xs.map(pos.source.offsetToLine(_)) - .map { lineNbr => - val prefix = s"${lineNbr + 1} |" - maxLen = math.max(maxLen, prefix.length) - (prefix, pos.lineContent(lineNbr).stripLineEnd) - } - .map { case (prefix, line) => - val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix) - hl"$lnum$line" - } + def render(offsetAndLine: (Int, String)): String = { + val (offset, line) = offsetAndLine + val lineNbr = pos.source.offsetToLine(offset) + val prefix = s"${lineNbr + 1} |" + maxLen = math.max(maxLen, prefix.length) + val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix).show + lnum + line.stripLineEnd + } + + def linesFrom(arr: Array[Char]): List[String] = { + def pred(c: Char) = (c: @switch) match { + case LF | CR | FF | SU => true + case _ => false + } + val (line, rest0) = arr.span(!pred(_)) + val (_, rest) = rest0.span(pred) + new String(line) :: { if (rest.isEmpty) Nil else linesFrom(rest) } + } + val syntax = + if (ctx.settings.color.value != "never") + SyntaxHighlighting(pos.linesSlice).toArray + else pos.linesSlice + val lines = linesFrom(syntax) val (before, after) = pos.beforeAndAfterPoint - (render(before), render(after), maxLen) + + ( + before.zip(lines).map(render), + after.zip(lines.drop(before.length)).map(render), + maxLen + ) } /** The column markers aligned under the error */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index bbd93eb30..7b56c8ed4 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -32,7 +32,6 @@ public enum ErrorMessageID { ByNameParameterNotSupportedID, WrongNumberOfTypeArgsID, IllegalVariableInPatternAlternativeID, - TypeParamsTypeExpectedID, IdentifierExpectedID, AuxConstructorNeedsNonImplicitParameterID, IncorrectRepeatedParameterSyntaxID, @@ -52,6 +51,10 @@ public enum ErrorMessageID { MixedLeftAndRightAssociativeOpsID, CantInstantiateAbstractClassOrTraitID, AnnotatedPrimaryConstructorRequiresModifierOrThisID, + OverloadedOrRecursiveMethodNeedsResultTypeID, + RecursiveValueNeedsResultTypeID, + CyclicReferenceInvolvingID, + CyclicReferenceInvolvingImplicitID, ; public int errorNumber() { diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index e367e9ab2..4c53fa496 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -18,6 +18,7 @@ import dotc.parsing.Tokens import printing.Highlighting._ import printing.Formatting import ErrorMessageID._ +import dotty.tools.dotc.core.SymDenotations.SymDenotation object messages { @@ -691,19 +692,6 @@ object messages { } } - case class TypeParamsTypeExpected(mods: untpd.Modifiers, identifier: TermName)(implicit ctx: Context) - extends Message(TypeParamsTypeExpectedID) { - val kind = "Syntax" - val msg = hl"""Expected ${"type"} keyword for type parameter $identifier""" - val explanation = - hl"""|This happens when you add modifiers like ${"private"} or ${"protected"} - |to your type parameter definition without adding the ${"type"} keyword. - | - |Add ${"type"} to your code, e.g.: - |${s"trait A[${mods.flags} type $identifier]"} - |""" - } - case class IdentifierExpected(identifier: String)(implicit ctx: Context) extends Message(IdentifierExpectedID) { val kind = "Syntax" @@ -1138,7 +1126,7 @@ object messages { | |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}"} | @@ -1147,7 +1135,7 @@ object messages { } case class AnnotatedPrimaryConstructorRequiresModifierOrThis(cls: Name)(implicit ctx: Context) - extends Message(AnnotatedPrimaryConstructorRequiresModifierOrThisID) { + extends Message(AnnotatedPrimaryConstructorRequiresModifierOrThisID) { val kind = "Syntax" val msg = hl"""${"private"}, ${"protected"}, or ${"this"} expected for annotated primary constructor""" val explanation = @@ -1160,4 +1148,48 @@ object messages { | ^^^^ |""".stripMargin } + + case class OverloadedOrRecursiveMethodNeedsResultType(tree: Names.TermName)(implicit ctx: Context) + extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) { + val kind = "Syntax" + val msg = hl"""overloaded or recursive method ${tree} needs return type""" + val explanation = + hl"""Case 1: ${tree} is overloaded + |If there are multiple methods named `${tree.name}` and at least one definition of + |it calls another, you need to specify the calling method's return type. + | + |Case 2: ${tree} is recursive + |If `${tree.name}` calls itself on any path, you need to specify its return type. + |""".stripMargin + } + + case class RecursiveValueNeedsResultType(tree: Names.TermName)(implicit ctx: Context) + extends Message(RecursiveValueNeedsResultTypeID) { + val kind = "Syntax" + val msg = hl"""recursive value ${tree.name} needs type""" + val explanation = + hl"""The definition of `${tree.name}` is recursive and you need to specify its type. + |""".stripMargin + } + + case class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) + extends Message(CyclicReferenceInvolvingID) { + val kind = "Syntax" + val msg = hl"""cyclic reference involving $denot""" + val explanation = + hl"""|$denot is declared as part of a cycle which makes it impossible for the + |compiler to decide upon ${denot.name}'s type. + |""".stripMargin + } + + case class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) + extends Message(CyclicReferenceInvolvingImplicitID) { + val kind = "Syntax" + val msg = hl"""cyclic reference involving implicit $cycleSym""" + val explanation = + hl"""|This happens when the right hand-side of $cycleSym's definition involves an implicit search. + |To avoid this error, give `${cycleSym.name}` an explicit type. + |""".stripMargin + } + } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 7f44af486..43202ef87 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -284,7 +284,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder case pt: PolyType => assert(start == 0) paramLists(pt.resultType) - case mt @ MethodType(pnames, ptypes) => + case mt @ MethodTpe(pnames, ptypes, restpe) => // TODO: We shouldn't have to work so hard to find the default parameters // of a method, Dotty should expose a convenience method for that, see #1143 val defaults = @@ -300,7 +300,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder val params = (pnames, ptypes, defaults).zipped.map((pname, ptype, isDefault) => new api.MethodParameter(pname.toString, apiType(ptype), isDefault, api.ParameterModifier.Plain)) - new api.ParameterList(params.toArray, mt.isImplicit) :: paramLists(mt.resultType, params.length) + new api.ParameterList(params.toArray, mt.isImplicit) :: paramLists(restpe, params.length) case _ => Nil } @@ -350,7 +350,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder case tp: NamedType => val sym = tp.symbol // Normalize package prefix to avoid instability of representation - val prefix = if (sym.isClass && sym.owner.is(Package)) + val prefix = if (sym.owner.is(Package)) sym.owner.thisType else tp.prefix @@ -358,7 +358,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder case TypeApplications.AppliedType(tycon, args) => def processArg(arg: Type): api.Type = arg match { case arg @ TypeBounds(lo, hi) => // Handle wildcard parameters - if (lo.eq(defn.NothingType) && hi.eq(defn.AnyType)) + if (lo.isDirectRef(defn.NothingClass) && hi.isDirectRef(defn.AnyClass)) Constants.emptyType else { val name = "_" diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala index 331fce46a..9f1e42e31 100644 --- a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala @@ -64,7 +64,7 @@ class CollectEntryPoints extends MiniPhaseTransform { val hasApproximate = possibles exists { m => m.info match { - case MethodType(_, p :: Nil) => + case MethodTpe(_, p :: Nil, _) => p.typeSymbol == defn.ArrayClass case _ => false } @@ -87,8 +87,8 @@ class CollectEntryPoints extends MiniPhaseTransform { m.symbol.info match { case t: PolyType => fail("main methods cannot be generic.") - case t@MethodType(paramNames, paramTypes) => - if (t.resultType :: paramTypes exists (_.typeSymbol.isAbstractType)) + case t: MethodType => + if (t.resultType :: t.paramTypes exists (_.typeSymbol.isAbstractType)) fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos) else javaPlatform.isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos) diff --git a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala index 0e187fc2e..59da78590 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala @@ -92,8 +92,8 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform arg } - val MethodType(_, formals) = tree.fun.tpe.widen - val args1 = tree.args.zipWithConserve(formals)(transformArg) + val mt @ MethodType(_) = tree.fun.tpe.widen + val args1 = tree.args.zipWithConserve(mt.paramTypes)(transformArg) cpy.Apply(tree)(tree.fun, args1) } diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index 258b7f234..ae3259509 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -32,11 +32,24 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = elimRepeated(tp) + + override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = + super.transform(ref) match { + case ref1: SymDenotation if (ref1 ne ref) && overridesJava(ref1.symbol) => + // This method won't override the corresponding Java method at the end of this phase, + // only the bridge added by `addVarArgsBridge` will. + ref1.copySymDenotation(initFlags = ref1.flags &~ Override) + case ref1 => + ref1 + } + override def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = sym is Method + private def overridesJava(sym: Symbol)(implicit ctx: Context) = sym.allOverriddenSymbols.exists(_ is JavaDefined) + private def elimRepeated(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match { - case tp @ MethodType(paramNames, paramTypes) => - val resultType1 = elimRepeated(tp.resultType) + case tp @ MethodTpe(paramNames, paramTypes, resultType) => + val resultType1 = elimRepeated(resultType) val paramTypes1 = if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) { val last = paramTypes.last.underlyingIfRepeated(tp.isJava) @@ -93,10 +106,9 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati */ override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { assert(ctx.phase == thisTransformer) - def overridesJava = tree.symbol.allOverriddenSymbols.exists(_ is JavaDefined) - if (tree.symbol.info.isVarArgsMethod && overridesJava) - addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next)) - else + if (tree.symbol.info.isVarArgsMethod && overridesJava(tree.symbol)) + addVarArgsBridge(tree) + else tree } @@ -120,6 +132,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati .appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp)) .appliedToArgss(vrefss1) }) + Thicket(ddef, bridgeDef) } diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 3857b405f..f9c7a8e1e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -40,8 +40,8 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => def isCompacted(sym: Symbol) = sym.isAnonymousFunction && { sym.info(ctx.withPhase(ctx.phase.next)) match { - case MethodType(nme.ALLARGS :: Nil, _) => true - case _ => false + case MethodType(nme.ALLARGS :: Nil) => true + case _ => false } } @@ -269,7 +269,7 @@ object Erasure extends TypeTestsCasts{ def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree = if (pt.isInstanceOf[FunProto]) tree else tree.tpe.widen match { - case MethodType(Nil, _) if tree.isTerm => + case MethodType(Nil) if tree.isTerm => adaptToType(tree.appliedToNone, pt) case tpw => if (pt.isInstanceOf[ProtoType] || tree.tpe <:< pt) @@ -697,9 +697,10 @@ object Erasure extends TypeTestsCasts{ val rhs = paramss.foldLeft(sel)((fun, vparams) => fun.tpe.widen match { - case MethodType(names, types) => Apply(fun, (vparams, types).zipped.map(adapt(_, _, untpd.EmptyTree))) - case a => error(s"can not resolve apply type $a") - + case mt: MethodType => + Apply(fun, (vparams, mt.paramTypes).zipped.map(adapt(_, _, untpd.EmptyTree))) + case a => + error(s"can not resolve apply type $a") }) adapt(rhs, resultType) }) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 91399f91a..7b15b7e54 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -53,7 +53,7 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => val applyRhs: Tree = applyDef.rhs val applyFn = applyDef.symbol.asTerm - val MethodType(paramNames, paramTypes) = applyFn.info + val MethodTpe(paramNames, paramTypes, _) = applyFn.info val isDefinedAtFn = applyFn.copy( name = nme.isDefinedAt, flags = Synthetic | Method, diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 44308012e..f17808e62 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -330,9 +330,9 @@ object ExplicitOuter { /** If `cls` has an outer parameter add one to the method type `tp`. */ def addParam(cls: ClassSymbol, tp: Type): Type = if (hasOuterParam(cls)) { - val mt @ MethodType(pnames, ptypes) = tp + val mt @ MethodTpe(pnames, ptypes, restpe) = tp mt.derivedMethodType( - nme.OUTER :: pnames, cls.owner.enclosingClass.typeRef :: ptypes, mt.resultType) + nme.OUTER :: pnames, cls.owner.enclosingClass.typeRef :: ptypes, restpe) } else tp /** If function in an apply node is a constructor that needs to be passed an @@ -391,7 +391,7 @@ object ExplicitOuter { /** The outer parameter definition of a constructor if it needs one */ def paramDefs(constr: Symbol): List[ValDef] = if (constr.isConstructor && hasOuterParam(constr.owner.asClass)) { - val MethodType(outerName :: _, outerType :: _) = constr.info + val MethodTpe(outerName :: _, outerType :: _, _) = constr.info val outerSym = ctx.newSymbol(constr, outerName, Param, outerType) ValDef(outerSym) :: Nil } diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 597146514..8328e43de 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -29,8 +29,11 @@ import StdNames._ * - eliminates some kinds of trees: Imports, NamedArgs * - stubs out native methods * - eliminates self tree in Template and self symbol in ClassInfo - * - collapsess all type trees to trees of class TypeTree + * - collapses all type trees to trees of class TypeTree * - converts idempotent expressions with constant types + * - drops branches of ifs using the rules + * if (true) A else B --> A + * if (false) A else B --> B */ class FirstTransform extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer => import ast.tpd._ @@ -148,7 +151,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo): Tree = { cpy.Template(impl)(self = EmptyValDef) } - + override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { if (ddef.symbol.hasAnnotation(defn.NativeAnnot)) { ddef.symbol.resetFlag(Deferred) @@ -168,13 +171,13 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota } override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = - if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) + if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else constToLiteral(tree) override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = - if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) + if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else constToLiteral(tree) - + override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo) = constToLiteral(tree) @@ -183,10 +186,16 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo) = constToLiteral(tree) - + override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo) = constToLiteral(tree) + override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) = + tree.cond match { + case Literal(Constant(c: Boolean)) => if (c) tree.thenp else tree.elsep + case _ => tree + } + // invariants: all modules have companion objects // all types are TypeTrees // all this types are explicit diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index 9e43fc999..0cb453b4c 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -12,8 +12,6 @@ import NameOps._ import ast._ import ast.Trees._ -import scala.reflect.internal.util.Collections - /** Provides methods to produce fully parameterized versions of instance methods, * where the `this` of the enclosing class is abstracted out in an extra leading * `$this` parameter and type parameters of the class become additional type @@ -107,8 +105,9 @@ trait FullParameterization { def resultType(mapClassParams: Type => Type) = { val thisParamType = mapClassParams(clazz.classInfo.selfType) val firstArgType = if (liftThisType) thisParamType & clazz.thisType else thisParamType - MethodType(nme.SELF :: Nil, firstArgType :: Nil)(mt => - mapClassParams(origResult).substThisUnlessStatic(clazz, MethodParam(mt, 0))) + MethodType(nme.SELF :: Nil)( + mt => firstArgType :: Nil, + mt => mapClassParams(origResult).substThisUnlessStatic(clazz, MethodParam(mt, 0))) } /** Replace class type parameters by the added type parameters of the polytype `pt` */ @@ -234,8 +233,8 @@ trait FullParameterization { fun.appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol))) else { // this type could have changed on forwarding. Need to insert a cast. - val args = Collections.map2(originalDef.vparamss, fun.tpe.paramTypess)((vparams, paramTypes) => - Collections.map2(vparams, paramTypes)((vparam, paramType) => { + val args = (originalDef.vparamss, fun.tpe.paramTypess).zipped.map((vparams, paramTypes) => + (vparams, paramTypes).zipped.map((vparam, paramType) => { assert(vparam.tpe <:< paramType.widen) // type should still conform to widened type ref(vparam.symbol).ensureConforms(paramType) }) @@ -254,10 +253,10 @@ object FullParameterization { def memberSignature(info: Type)(implicit ctx: Context): Signature = info match { case info: PolyType => memberSignature(info.resultType) - case info @ MethodType(nme.SELF :: Nil, _) => - info.resultType.ensureMethodic.signature - case info @ MethodType(nme.SELF :: otherNames, thisType :: otherTypes) => - info.derivedMethodType(otherNames, otherTypes, info.resultType).signature + case MethodTpe(nme.SELF :: Nil, _, restpe) => + restpe.ensureMethodic.signature + case info @ MethodTpe(nme.SELF :: otherNames, thisType :: otherTypes, restpe) => + info.derivedMethodType(otherNames, otherTypes, restpe).signature case _ => Signature.NotAMethod } diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index b603a53dc..7578b57f1 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -352,12 +352,12 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform } private def liftedInfo(local: Symbol)(implicit ctx: Context): Type = local.info match { - case mt @ MethodType(pnames, ptypes) => + case MethodTpe(pnames, ptypes, restpe) => val ps = proxies(local) MethodType( ps.map(_.name.asTermName) ++ pnames, ps.map(_.info) ++ ptypes, - mt.resultType) + restpe) case info => info } diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index a6ac71286..2035fb04b 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -139,7 +139,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos) val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType(Nil, tpe), coord = x.pos) - val result = ref(holderSymbol).select(lazyNme.value) + val result = ref(holderSymbol).select(lazyNme.value).withPos(x.pos) val flag = ref(holderSymbol).select(lazyNme.initialized) val initer = valueInitter.changeOwnerAfter(x.symbol, initSymbol, this) val initBody = diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index a72e10681..859ac8b06 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -27,7 +27,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) { val (superArgs, superParamNames) = impl.parents match { case superCall @ Apply(fn, args) :: _ => fn.tpe.widen match { - case MethodType(paramNames, _) => (args, paramNames) + case MethodType(paramNames) => (args, paramNames) case _ => (Nil, Nil) } case _ => (Nil, Nil) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 7c49e68dd..7576ccc05 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -30,8 +30,6 @@ import dotty.tools.dotc.util.Positions.Position import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.Flags -import scala.reflect.internal.util.Collections - /** This transform eliminates patterns. Right now it's a dummy. * Awaiting the real pattern matcher. * elimRepeated is required @@ -166,7 +164,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { } def emitValDefs: List[ValDef] = { - Collections.map2(lhs, rhs)((symbol, tree) => ValDef(symbol.asTerm, tree.ensureConforms(symbol.info))) + (lhs, rhs).zipped.map((symbol, tree) => ValDef(symbol.asTerm, tree.ensureConforms(symbol.info))) } } object NoRebindings extends Rebindings(Nil, Nil) @@ -609,7 +607,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { // only store binders actually used val (subPatBindersStored, subPatRefsStored) = stored.filter{case (b, _) => usedBinders(b)}.unzip - Block(Collections.map2(subPatBindersStored.toList, subPatRefsStored.toList)((bind, ref) => { + Block((subPatBindersStored.toList, subPatRefsStored.toList).zipped.map((bind, ref) => { // required in case original pattern had a more precise type // eg case s@"foo" => would be otherwise translated to s with type String instead of String("foo") def refTpeWiden = ref.tpe.widen diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 7a4af647f..51e2469b2 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -446,7 +446,7 @@ class TreeChecker extends Phase with SymTransformer { super.typedStats(trees, exprOwner) } - override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol], forcedDefined: Boolean = false)(implicit ctx: Context): Tree = + override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(implicit ctx: Context): Tree = tree override def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context) = { diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index e9df12b42..5dcf16b62 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -178,6 +178,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => */ protected def normalizedFun: Tree + protected def typeOfArg(arg: Arg): Type + /** If constructing trees, pull out all parts of the function * which are not idempotent into separate prefix definitions */ @@ -213,16 +215,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic => protected def init() = methType match { case methType: MethodType => // apply the result type constraint, unless method type is dependent - if (!methType.isDependent) { - val savedConstraint = ctx.typerState.constraint - if (!constrainResult(methType.resultType, resultType)) - if (ctx.typerState.isCommittable) - // defer the problem until after the application; - // it might be healed by an implicit conversion - assert(ctx.typerState.constraint eq savedConstraint) - else - fail(err.typeMismatchMsg(methType.resultType, resultType)) - } + val resultApprox = resultTypeApprox(methType) + val savedConstraint = ctx.typerState.constraint + if (!constrainResult(resultApprox, resultType)) + if (ctx.typerState.isCommittable) + // defer the problem until after the application; + // it might be healed by an implicit conversion + assert(ctx.typerState.constraint eq savedConstraint) + else + fail(err.typeMismatchMsg(methType.resultType, resultType)) // match all arguments with corresponding formal parameters matchArgs(orderedArgs, methType.paramTypes, 0) case _ => @@ -381,8 +382,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (success) formals match { case formal :: formals1 => - def addTyped(arg: Arg, formal: Type) = + /** Add result of typing argument `arg` against parameter type `formal`. + * @return A type transformation to apply to all arguments following this one. + */ + def addTyped(arg: Arg, formal: Type): Type => Type = { addArg(typedArg(arg, formal), formal) + if (methodType.isParamDependent) + _.substParam(MethodParam(methodType, n), typeOfArg(arg)) + else + identity + } def missingArg(n: Int): Unit = { val pname = methodType.paramNames(n) @@ -396,8 +405,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val getter = findDefaultGetter(n + numArgs(normalizedFun)) if (getter.isEmpty) missingArg(n) else { - addTyped(treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), formal) - matchArgs(args1, formals1, n + 1) + val substParam = addTyped( + treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), + formal) + matchArgs(args1, formals1.mapconserve(substParam), n + 1) } } @@ -421,8 +432,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case EmptyTree :: args1 => tryDefault(n, args1) case arg :: args1 => - addTyped(arg, formal) - matchArgs(args1, formals1, n + 1) + val substParam = addTyped(arg, formal) + matchArgs(args1, formals1.mapconserve(substParam), n + 1) case nil => tryDefault(n, args) } @@ -478,6 +489,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def argType(arg: Tree, formal: Type): Type = normalize(arg.tpe, formal) def treeToArg(arg: Tree): Tree = arg def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg) + def typeOfArg(arg: Tree): Type = arg.tpe def harmonizeArgs(args: List[Tree]) = harmonize(args) } @@ -495,6 +507,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def argType(arg: Type, formal: Type): Type = arg def treeToArg(arg: Tree): Type = arg.tpe def isVarArg(arg: Type): Boolean = arg.isRepeatedParam + def typeOfArg(arg: Type): Type = arg def harmonizeArgs(args: List[Type]) = harmonizeTypes(args) } @@ -593,6 +606,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => extends TypedApply(app, fun, methRef, proto.args, resultType) { def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal.widenExpr) def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg) + def typeOfArg(arg: untpd.Tree) = proto.typeOfArg(arg) } /** Subclass of Application for type checking an Apply node with typed arguments. */ @@ -604,6 +618,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // not match the abstract method in Application and an abstract class error results. def typedArg(arg: tpd.Tree, formal: Type): TypedArg = arg def treeToArg(arg: Tree): Tree = arg + def typeOfArg(arg: Tree) = arg.tpe } /** If `app` is a `this(...)` constructor call, the this-call argument context, @@ -1100,10 +1115,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => /** Drop any implicit parameter section */ def stripImplicit(tp: Type): Type = tp match { - case mt: ImplicitMethodType if !mt.isDependent => - mt.resultType - // todo: make sure implicit method types are not dependent? - // but check test case in /tests/pos/depmet_implicit_chaining_zw.scala + case mt: ImplicitMethodType => + resultTypeApprox(mt) case pt: PolyType => pt.derivedPolyType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType)) case _ => @@ -1266,7 +1279,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def sizeFits(alt: TermRef, tp: Type): Boolean = tp match { case tp: PolyType => sizeFits(alt, tp.resultType) - case MethodType(_, ptypes) => + case tp: MethodType => + val ptypes = tp.paramTypes val numParams = ptypes.length def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam def hasDefault = alt.symbol.hasDefaultParams @@ -1384,7 +1398,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => else WildcardType) val commonFormal = defn.FunctionOf(commonParamTypes, WildcardType) overload.println(i"pretype arg $arg with expected type $commonFormal") - pt.typedArg(arg, commonFormal) + pt.typedArg(arg, commonFormal)(ctx.addMode(Mode.ImplicitsEnabled)) } } } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 48f9243f7..b43391592 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -327,7 +327,7 @@ object Checking { if (!sym.is(Deferred)) fail(i"`@native' members may not have implementation") } - else if (sym.is(Deferred, butNot = Param) && !sym.isSelfSym) { + else if (sym.is(Deferred, butNot = Param) && !sym.isType && !sym.isSelfSym) { if (!sym.owner.isClass || sym.owner.is(Module) || sym.owner.isAnonymousClass) fail(i"only classes can have declared but undefined members$varNote") checkWithDeferred(Private) @@ -357,7 +357,7 @@ object Checking { */ def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = { class NotPrivate extends TypeMap { - var errors: List[String] = Nil + var errors: List[() => String] = Nil def accessBoundary(sym: Symbol): Symbol = if (sym.is(Private) || !sym.owner.isClass) sym.owner @@ -384,7 +384,7 @@ object Checking { var tp1 = if (isLeaked(tp.symbol)) { errors = - em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}" :: errors + (() => em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}") :: errors tp } else mapOver(tp) @@ -408,7 +408,7 @@ object Checking { } val notPrivate = new NotPrivate val info = notPrivate(sym.info) - notPrivate.errors.foreach(ctx.errorOrMigrationWarning(_, pos)) + notPrivate.errors.foreach(error => ctx.errorOrMigrationWarning(error(), pos)) info } @@ -441,7 +441,6 @@ object Checking { case List(param) => if (param.is(Mutable)) ctx.error("value class parameter must not be a var", param.pos) - case _ => ctx.error("value class needs to have exactly one val parameter", clazz.pos) } @@ -625,6 +624,24 @@ trait Checking { case _ => } } + + /** Check that method parameter types do not reference their own parameter + * or later parameters in the same parameter section. + */ + def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = vparams match { + case vparam :: vparams1 => + val check = new TreeTraverser { + def traverse(tree: Tree)(implicit ctx: Context) = tree match { + case id: Ident if vparams.exists(_.symbol == id.symbol) => + ctx.error("illegal forward reference to method parameter", id.pos) + case _ => + traverseChildren(tree) + } + } + check.traverse(vparam.tpt) + checkNoForwardDependencies(vparams1) + case Nil => + } } trait NoChecking extends Checking { @@ -642,4 +659,5 @@ trait NoChecking extends Checking { override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = () override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = () + override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = () } diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 0978c2c1e..a1690955f 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -28,24 +28,22 @@ object ErrorReporting { def cyclicErrorMsg(ex: CyclicReference)(implicit ctx: Context) = { val cycleSym = ex.denot.symbol - def errorMsg(msg: String, cx: Context): String = + def errorMsg(msg: Message, cx: Context): Message = if (cx.mode is Mode.InferringReturnType) { cx.tree match { case tree: untpd.DefDef if !tree.tpt.typeOpt.exists => - em"overloaded or recursive method ${tree.name} needs result type" + OverloadedOrRecursiveMethodNeedsResultType(tree.name) case tree: untpd.ValDef if !tree.tpt.typeOpt.exists => - em"recursive value ${tree.name} needs type" + RecursiveValueNeedsResultType(tree.name) case _ => errorMsg(msg, cx.outer) } } else msg if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm) - em"""cyclic reference involving implicit $cycleSym - |This happens when the right hand-side of $cycleSym's definition involves an implicit search. - |To avoid the error, give $cycleSym an explicit type.""" + CyclicReferenceInvolvingImplicit(cycleSym) else - errorMsg(ex.show, ctx) + errorMsg(ex.toMessage, ctx) } def wrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree], pos: Position)(implicit ctx: Context) = diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index e7e7ece78..57c1808c9 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -59,8 +59,8 @@ object EtaExpansion { */ def liftArgs(defs: mutable.ListBuffer[Tree], methRef: Type, args: List[Tree])(implicit ctx: Context) = methRef.widen match { - case MethodType(paramNames, paramTypes) => - (args, paramNames, paramTypes).zipped map { (arg, name, tp) => + case mt: MethodType => + (args, mt.paramNames, mt.paramTypes).zipped map { (arg, name, tp) => if (tp.isInstanceOf[ExprType]) arg else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$") } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index d5afae90c..681045cc4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -82,11 +82,29 @@ object Implicits { case tpw: TermRef => false // can't discard overloaded refs case tpw => - //if (ctx.typer.isApplicable(tp, argType :: Nil, resultType)) - // println(i"??? $tp is applicable to $this / typeSymbol = ${tpw.typeSymbol}") - !tpw.derivesFrom(defn.FunctionClass(1)) || - ref.symbol == defn.Predef_conforms // - // as an implicit conversion, Predef.$conforms is a no-op, so exclude it + // Only direct instances of Function1 and direct or indirect instances of <:< are eligible as views. + // However, Predef.$conforms is not eligible, because it is a no-op. + // + // In principle, it would be cleanest if only implicit methods qualified + // as implicit conversions. We could achieve that by having standard conversions like + // this in Predef: + // + // implicit def convertIfConforms[A, B](x: A)(implicit ev: A <:< B): B = ev(a) + // implicit def convertIfConverter[A, B](x: A)(implicit ev: ImplicitConverter[A, B]): B = ev(a) + // + // (Once `<:<` inherits from `ImplicitConverter` we only need the 2nd one.) + // But clauses like this currently slow down implicit search a lot, because + // they are eligible for all pairs of types, and therefore are tried too often. + // We emulate instead these conversions directly in the search. + // The reason for leaving out `Predef_conforms` is that we know it adds + // nothing since it only relates subtype with supertype. + // + // We keep the old behavior under -language:Scala2. + val isFunctionInS2 = ctx.scala2Mode && tpw.derivesFrom(defn.FunctionClass(1)) + val isImplicitConverter = tpw.derivesFrom(defn.Predef_ImplicitConverter) + val isConforms = + tpw.derivesFrom(defn.Predef_Conforms) && ref.symbol != defn.Predef_conforms + !(isFunctionInS2 || isImplicitConverter || isConforms) } def discardForValueType(tpw: Type): Boolean = tpw match { @@ -496,9 +514,15 @@ trait Implicits { self: Typer => || (to isRef defn.UnitClass) || (from.tpe isRef defn.NothingClass) || (from.tpe isRef defn.NullClass) + || !(ctx.mode is Mode.ImplicitsEnabled) || (from.tpe eq NoPrefix)) NoImplicitMatches - else - try inferImplicit(to.stripTypeVar.widenExpr, from, from.pos) + else { + def adjust(to: Type) = to.stripTypeVar.widenExpr match { + case SelectionProto(name, memberProto, compat, true) => + SelectionProto(name, memberProto, compat, privateOK = false) + case tp => tp + } + try inferImplicit(adjust(to), from, from.pos) catch { case ex: AssertionError => implicits.println(s"view $from ==> $to") @@ -506,6 +530,7 @@ trait Implicits { self: Typer => implicits.println(TypeComparer.explained(implicit ctx => from.tpe <:< to)) throw ex } + } } /** Find an implicit argument for parameter `formal`. diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index d5f171fe3..f2ad1f7c9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -484,46 +484,91 @@ class Namer { typer: Typer => /** Create top-level symbols for statements and enter them into symbol table */ def index(stats: List[Tree])(implicit ctx: Context): Context = { - val classDef = mutable.Map[TypeName, TypeDef]() - val moduleDef = mutable.Map[TypeName, TypeDef]() + // module name -> (stat, moduleCls | moduleVal) + val moduleClsDef = mutable.Map[TypeName, (Tree, TypeDef)]() + val moduleValDef = mutable.Map[TermName, (Tree, ValDef)]() + + /** Remove the subtree `tree` from the expanded tree of `mdef` */ + def removeInExpanded(mdef: Tree, tree: Tree): Unit = { + val Thicket(trees) = expanded(mdef) + mdef.putAttachment(ExpandedTree, Thicket(trees.filter(_ != tree))) + } + + /** Merge the module class `modCls` in the expanded tree of `mdef` with the given stats */ + def mergeModuleClass(mdef: Tree, modCls: TypeDef, stats: List[Tree]): TypeDef = { + var res: TypeDef = null + val Thicket(trees) = expanded(mdef) + val merged = trees.map { tree => + if (tree == modCls) { + val impl = modCls.rhs.asInstanceOf[Template] + res = cpy.TypeDef(modCls)(rhs = cpy.Template(impl)(body = stats ++ impl.body)) + res + } + else tree + } + + mdef.putAttachment(ExpandedTree, Thicket(merged)) + + res + } + + /** Merge `fromCls` of `fromStat` into `toCls` of `toStat` + * if the former is synthetic and the latter not. + * + * Note: + * 1. `fromStat` and `toStat` could be the same stat + * 2. `fromCls` and `toCls` are necessarily different + */ + def mergeIfSynthetic(fromStat: Tree, fromCls: TypeDef, toStat: Tree, toCls: TypeDef): Unit = + if (fromCls.mods.is(Synthetic) && !toCls.mods.is(Synthetic)) { + removeInExpanded(fromStat, fromCls) + val mcls = mergeModuleClass(toStat, toCls, fromCls.rhs.asInstanceOf[Template].body) + moduleClsDef(fromCls.name) = (toStat, mcls) + } /** Merge the definitions of a synthetic companion generated by a case class * and the real companion, if both exist. */ def mergeCompanionDefs() = { - for (cdef @ TypeDef(name, _) <- stats) - if (cdef.isClassDef) { - classDef(name) = cdef - cdef.attachmentOrElse(ExpandedTree, cdef) match { - case Thicket(cls :: mval :: (mcls @ TypeDef(mname, _: Template)) :: crest) - if name.moduleClassName == mname => - moduleDef(name) = mcls - case _ => - } - } - for (mdef @ ModuleDef(name, _) <- stats if !mdef.mods.is(Flags.Package)) { - val typName = name.toTypeName - // Expansion of object is a flattened thicket with the first two elements being: - // module val :: module class :: rest - val Thicket(vdef :: (mcls @ TypeDef(_, impl: Template)) :: rest) = expanded(mdef) - moduleDef(typName) = mcls - classDef get name.toTypeName match { - case Some(cdef) => - cdef.attachmentOrElse(ExpandedTree, cdef) match { - case Thicket(cls :: mval :: TypeDef(mname, compimpl: Template) :: crest) - if name.moduleClassName == mname => - val mcls1 = cpy.TypeDef(mcls)( - rhs = cpy.Template(impl)(body = compimpl.body ++ impl.body)) - mdef.putAttachment(ExpandedTree, Thicket(vdef :: mcls1 :: rest)) - moduleDef(typName) = mcls1 - cdef.putAttachment(ExpandedTree, Thicket(cls :: crest)) + def valid(mdef: MemberDef): Boolean = mdef.mods.is(Module, butNot = Package) + + for (stat <- stats) + expanded(stat) match { + case Thicket(trees) => // companion object always expands to thickets + trees.map { + case mcls @ TypeDef(name, impl: Template) if valid(mcls) => + moduleClsDef.get(name) match { + case Some((stat1, mcls1@TypeDef(_, impl1: Template))) => + mergeIfSynthetic(stat, mcls, stat1, mcls1) + mergeIfSynthetic(stat1, mcls1, stat, mcls) + case None => + moduleClsDef(name) = (stat, mcls) + } + + case vdef @ ValDef(name, _, _) if valid(vdef) => + moduleValDef.get(name) match { + case Some((stat1, vdef1)) => + if (vdef.mods.is(Synthetic) && !vdef1.mods.is(Synthetic)) + removeInExpanded(stat, vdef) + else if (!vdef.mods.is(Synthetic) && vdef1.mods.is(Synthetic)) { + removeInExpanded(stat1, vdef1) + moduleValDef(name) = (stat, vdef) + } + else { + // double definition of objects or case classes, handled elsewhere + } + case None => + moduleValDef(name) = (stat, vdef) + } + case _ => } - case none => + case _ => + } - } } + /** Create links between companion object and companion class */ def createLinks(classTree: TypeDef, moduleTree: TypeDef)(implicit ctx: Context) = { val claz = ctx.denotNamed(classTree.name.encode).symbol val modl = ctx.denotNamed(moduleTree.name.encode).symbol @@ -532,8 +577,29 @@ class Namer { typer: Typer => } def createCompanionLinks(implicit ctx: Context): Unit = { + val classDef = mutable.Map[TypeName, TypeDef]() + val moduleDef = mutable.Map[TypeName, TypeDef]() + + def updateCache(cdef: TypeDef): Unit = { + if (!cdef.isClassDef || cdef.mods.is(Package)) return + + if (cdef.mods.is(ModuleClass)) moduleDef(cdef.name) = cdef + else classDef(cdef.name) = cdef + } + + for (stat <- stats) + expanded(stat) match { + case cdef : TypeDef => updateCache(cdef) + case Thicket(trees) => + trees.map { + case cdef: TypeDef => updateCache(cdef) + case _ => + } + case _ => + } + for (cdef @ TypeDef(name, _) <- classDef.values) { - moduleDef.getOrElse(name, EmptyTree) match { + moduleDef.getOrElse(name.moduleClassName, EmptyTree) match { case t: TypeDef => createLinks(cdef, t) case EmptyTree => @@ -753,11 +819,10 @@ class Namer { typer: Typer => /* Check parent type tree `parent` for the following well-formedness conditions: * (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix) * (2) If may not derive from itself - * (3) Overriding type parameters must be correctly forwarded. (@see checkTypeParamOverride) - * (4) The class is not final - * (5) If the class is sealed, it is defined in the same compilation unit as the current class + * (3) The class is not final + * (4) If the class is sealed, it is defined in the same compilation unit as the current class */ - def checkedParentType(parent: untpd.Tree, paramAccessors: List[Symbol]): Type = { + def checkedParentType(parent: untpd.Tree): Type = { val ptype = parentType(parent)(ctx.superCallContext) if (cls.isRefinementClass) ptype else { @@ -772,8 +837,6 @@ class Namer { typer: Typer => ctx.error(i"cyclic inheritance: $cls extends itself$addendum", parent.pos) defn.ObjectType } - else if (!paramAccessors.forall(checkTypeParamOverride(pt, _))) - defn.ObjectType else { val pclazz = pt.typeSymbol if (pclazz.is(Final)) @@ -785,47 +848,7 @@ class Namer { typer: Typer => } } - /* Check that every parameter with the same name as a visible named parameter in the parent - * class satisfies the following two conditions: - * (1) The overriding parameter is also named (i.e. not local/name mangled). - * (2) The overriding parameter is passed on directly to the parent parameter, or the - * parent parameter is not fully defined. - * @return true if conditions are satisfied, false otherwise. - */ - def checkTypeParamOverride(parent: Type, paramAccessor: Symbol): Boolean = { - var ok = true - val pname = paramAccessor.name - - def illegal(how: String): Unit = { - ctx.error(em"Illegal override of public type parameter $pname in $parent$how", paramAccessor.pos) - ok = false - } - - def checkAlias(tp: Type): Unit = tp match { - case tp: RefinedType => - if (tp.refinedName == pname) - tp.refinedInfo match { - case TypeAlias(alias) => - alias match { - case TypeRef(pre, name1) if name1 == pname && (pre =:= cls.thisType) => - // OK, parameter is passed on directly - case _ => - illegal(em".\nParameter is both redeclared and instantiated with $alias.") - } - case _ => // OK, argument is not fully defined - } - else checkAlias(tp.parent) - case _ => - } - if (parent.nonPrivateMember(paramAccessor.name).symbol.is(Param)) - if (paramAccessor is Private) - illegal("\nwith private parameter. Parameter definition needs to be prefixed with `type'.") - else - checkAlias(parent) - ok - } - - addAnnotations(denot.symbol, original) + addAnnotations(denot.symbol, original) val selfInfo = if (self.isEmpty) NoType @@ -853,8 +876,7 @@ class Namer { typer: Typer => indexAndAnnotate(rest)(inClassContext(selfInfo)) - val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList - val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_, tparamAccessors))) + val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_))) val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls) typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs") @@ -862,8 +884,6 @@ class Namer { typer: Typer => Checking.checkWellFormed(cls) if (isDerivedValueClass(cls)) cls.setFlag(Final) - cls.setApplicableFlags( - (NoInitsInterface /: impl.body)((fs, stat) => fs & defKind(stat))) cls.info = avoidPrivateLeaks(cls, cls.pos) } } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index d666b563e..f7dd725c8 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -57,19 +57,14 @@ object ProtoTypes { case pt: FunProto => mt match { case mt: MethodType => - mt.isDependent || constrainResult(mt.resultType, pt.resultType) + constrainResult(resultTypeApprox(mt), pt.resultType) case _ => true } case _: ValueTypeOrProto if !disregardProto(pt) => - mt match { - case mt: MethodType => - mt.isDependent || isCompatible(normalize(mt, pt), pt) - case _ => - isCompatible(mt, pt) - } - case _: WildcardType => - isCompatible(mt, pt) + isCompatible(normalize(mt, pt), pt) + case pt: WildcardType if pt.optBounds.exists => + isCompatible(normalize(mt, pt), pt) case _ => true } @@ -95,12 +90,12 @@ object ProtoTypes { * * [ ].name: proto */ - abstract case class SelectionProto(val name: Name, val memberProto: Type, val compat: Compatibility) + abstract case class SelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean) extends CachedProxyType with ProtoType with ValueTypeOrProto { override def isMatchedBy(tp1: Type)(implicit ctx: Context) = { name == nme.WILDCARD || { - val mbr = tp1.member(name) + val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name) def qualifies(m: SingleDenotation) = memberProto.isRef(defn.UnitClass) || compat.normalizedCompatible(m.info, memberProto) @@ -115,11 +110,11 @@ object ProtoTypes { def derivedSelectionProto(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context) = if ((name eq this.name) && (memberProto eq this.memberProto) && (compat eq this.compat)) this - else SelectionProto(name, memberProto, compat) + else SelectionProto(name, memberProto, compat, privateOK) override def equals(that: Any): Boolean = that match { case that: SelectionProto => - (name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat) + (name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat) && (privateOK == that.privateOK) case _ => false } @@ -129,14 +124,18 @@ object ProtoTypes { override def deepenProto(implicit ctx: Context) = derivedSelectionProto(name, memberProto.deepenProto, compat) - override def computeHash = addDelta(doHash(name, memberProto), if (compat eq NoViewsAllowed) 1 else 0) + override def computeHash = { + val delta = (if (compat eq NoViewsAllowed) 1 else 0) | (if (privateOK) 2 else 0) + addDelta(doHash(name, memberProto), delta) + } } - class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility) extends SelectionProto(name, memberProto, compat) + class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean) + extends SelectionProto(name, memberProto, compat, privateOK) object SelectionProto { - def apply(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context): SelectionProto = { - val selproto = new CachedSelectionProto(name, memberProto, compat) + def apply(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)(implicit ctx: Context): SelectionProto = { + val selproto = new CachedSelectionProto(name, memberProto, compat, privateOK) if (compat eq NoViewsAllowed) unique(selproto) else selproto } } @@ -148,7 +147,7 @@ object ProtoTypes { if (name.isConstructorName) WildcardType else tp match { case tp: UnapplyFunProto => new UnapplySelectionProto(name) - case tp => SelectionProto(name, IgnoredProto(tp), typer) + case tp => SelectionProto(name, IgnoredProto(tp), typer, privateOK = true) } /** A prototype for expressions [] that are in some unspecified selection operation @@ -159,10 +158,10 @@ object ProtoTypes { * operation is further selection. In this case, the expression need not be a value. * @see checkValue */ - @sharable object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType, NoViewsAllowed) + @sharable object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType, NoViewsAllowed, true) /** A prototype for selections in pattern constructors */ - class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed) + class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed, true) trait ApplyingProto extends ProtoType @@ -238,6 +237,12 @@ object ProtoTypes { typer.adapt(targ, formal, arg) } + /** The type of the argument `arg`. + * @pre `arg` has been typed before + */ + def typeOfArg(arg: untpd.Tree)(implicit ctx: Context): Type = + myTypedArg(arg).tpe + private var myTupled: Type = NoType /** The same proto-type but with all arguments combined in a single tuple */ @@ -394,6 +399,26 @@ object ProtoTypes { /** Same as `constrained(pt, EmptyTree)`, but returns just the created polytype */ def constrained(pt: PolyType)(implicit ctx: Context): PolyType = constrained(pt, EmptyTree)._1 + /** Create a new polyparam that represents a dependent method parameter singleton */ + def newDepPolyParam(tp: Type)(implicit ctx: Context): PolyParam = { + val poly = PolyType(ctx.freshName(nme.DEP_PARAM_PREFIX).toTypeName :: Nil, 0 :: Nil)( + pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil, + pt => defn.AnyType) + ctx.typeComparer.addToConstraint(poly, Nil) + PolyParam(poly, 0) + } + + /** The result type of `mt`, where all references to parameters of `mt` are + * replaced by either wildcards (if typevarsMissContext) or polyparams. + */ + def resultTypeApprox(mt: MethodType)(implicit ctx: Context): Type = + if (mt.isDependent) { + def replacement(tp: Type) = + if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepPolyParam(tp) + mt.resultType.substParams(mt, mt.paramTypes.map(replacement)) + } + else mt.resultType + /** The normalized form of a type * - unwraps polymorphic types, tracking their parameters in the current constraint * - skips implicit parameters; if result type depends on implicit parameter, @@ -413,22 +438,18 @@ object ProtoTypes { tp.widenSingleton match { case poly: PolyType => normalize(constrained(poly).resultType, pt) case mt: MethodType => - if (mt.isImplicit) - if (mt.isDependent) - mt.resultType.substParams(mt, mt.paramTypes.map(Function.const(WildcardType))) - else mt.resultType - else - if (mt.isDependent) tp - else { - val rt = normalize(mt.resultType, pt) + if (mt.isImplicit) resultTypeApprox(mt) + else if (mt.isDependent) tp + else { + val rt = normalize(mt.resultType, pt) pt match { case pt: IgnoredProto => mt case pt: ApplyingProto => mt.derivedMethodType(mt.paramNames, mt.paramTypes, rt) case _ => val ft = defn.FunctionOf(mt.paramTypes, rt) if (mt.paramTypes.nonEmpty || ft <:< pt) ft else rt - } } + } case et: ExprType => et.resultType case _ => tp } diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 3252ead47..6080c6644 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -85,8 +85,8 @@ class ReTyper extends Typer { override def encodeName(tree: untpd.NameTree)(implicit ctx: Context) = tree override def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree = fun.tpe match { - case mt @ MethodType(_, formals) => - val args: List[Tree] = tree.args.zipWithConserve(formals)(typedExpr(_, _)).asInstanceOf[List[Tree]] + case mt: MethodType => + val args: List[Tree] = tree.args.zipWithConserve(mt.paramTypes)(typedExpr(_, _)).asInstanceOf[List[Tree]] assignType(untpd.cpy.Apply(tree)(fun, args), fun, args) case _ => super.handleUnexpectedFunType(tree, fun) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 7c573d23c..d61f5fa68 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -241,8 +241,6 @@ object RefChecks { isDefaultGetter(member.name) || // default getters are not checked for compatibility memberTp.overrides(otherTp) - def domain(sym: Symbol): Set[Name] = sym.info.namedTypeParams.map(_.name) - //Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG // return if we already checked this combination elsewhere @@ -344,9 +342,6 @@ object RefChecks { overrideError("cannot be used here - only term macros can override term macros") } else if (!compatibleTypes) { overrideError("has incompatible type" + err.whyNoMatchStr(memberTp, otherTp)) - } else if (member.isType && domain(member) != domain(other)) { - overrideError("has different named type parameters: "+ - i"[${domain(member).toList}%, %] instead of [${domain(other).toList}%, %]") } else { checkOverrideDeprecated() } @@ -744,11 +739,7 @@ import RefChecks._ * * 2. It warns about references to symbols labeled deprecated or migration. - * 3. It performs the following transformations: - * - * - if (true) A else B --> A - * if (false) A else B --> B - * - macro definitions are eliminated. + * 3. It eliminates macro definitions. * * 4. It makes members not private where necessary. The following members * cannot be private in the Java model: @@ -771,6 +762,9 @@ class RefChecks extends MiniPhase { thisTransformer => override def phaseName: String = "refchecks" + // Needs to run after ElimRepeated for override checks involving varargs methods + override def runsAfter = Set(classOf[ElimRepeated]) + val treeTransform = new Transform(NoLevelInfo) class Transform(currentLevel: RefChecks.OptLevelInfo = RefChecks.NoLevelInfo) extends TreeTransform { @@ -838,12 +832,6 @@ class RefChecks extends MiniPhase { thisTransformer => tree } - override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) = - tree.cond.tpe match { - case ConstantType(value) => if (value.booleanValue) tree.thenp else tree.elsep - case _ => tree - } - override def transformNew(tree: New)(implicit ctx: Context, info: TransformerInfo) = { currentLevel.enterReference(tree.tpe.typeSymbol, tree.pos) tree diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 53ce5555b..6e774e38e 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -199,10 +199,7 @@ trait TypeAssigner { } } else if (d.symbol is TypeParamAccessor) - if (d.info.isAlias) - ensureAccessible(d.info.bounds.hi, superAccess, pos) - else // It's a named parameter, use the non-symbolic representation to pick up inherited versions as well - d.symbol.owner.thisType.select(d.symbol.name) + ensureAccessible(d.info.bounds.hi, superAccess, pos) else ctx.makePackageObjPrefixExplicit(tpe withDenot d) case _ => @@ -318,10 +315,10 @@ trait TypeAssigner { def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { val ownType = fn.tpe.widen match { - case fntpe @ MethodType(_, ptypes) => - if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) + case fntpe: MethodType => + if (sameLength(fntpe.paramTypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) else - errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${ptypes.length}, found: ${args.length}", tree.pos) + errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramTypes.length}, found: ${args.length}", tree.pos) case t => errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos) } @@ -452,23 +449,10 @@ trait TypeAssigner { } def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = { + assert(!hasNamedArg(args)) val tparams = tycon.tpe.typeParams - lazy val ntparams = tycon.tpe.namedTypeParams - def refineNamed(tycon: Type, arg: Tree) = arg match { - case ast.Trees.NamedArg(name, argtpt) => - // Dotty deviation: importing ast.Trees._ and matching on NamedArg gives a cyclic ref error - val tparam = tparams.find(_.paramName == name) match { - case Some(tparam) => tparam - case none => ntparams.find(_.name == name).getOrElse(NoSymbol) - } - if (tparam.isTypeParam) RefinedType(tycon, name, argtpt.tpe.toBounds(tparam)) - else errorType(i"$tycon does not have a parameter or abstract type member named $name", arg.pos) - case _ => - errorType(s"named and positional type arguments may not be mixed", arg.pos) - } val ownType = - if (hasNamedArg(args)) (tycon.tpe /: args)(refineNamed) - else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) + if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.pos) tree.withType(ownType) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 33e320ce5..d4a9744e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -625,14 +625,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit block.tpe namedPartsWith (tp => locals.contains(tp.symbol)) } - /** Check that expression's type can be expressed without references to locally defined - * symbols. The following two remedies are tried before giving up: - * 1. If the expected type of the expression is fully defined, pick it as the - * type of the result expressed by adding a type ascription. - * 2. If (1) fails, force all type variables so that the block's type is - * fully defined and try again. + /** Ensure that an expression's type can be expressed without references to locally defined + * symbols. This is done by adding a type ascription of a widened type that does + * not refer to the locally defined symbols. The widened type is computed using + * `TyperAssigner#avoid`. However, if the expected type is fully defined and not + * a supertype of the widened type, we ascribe with the expected type instead. + * + * There's a special case having to do with anonymous classes. Sometimes the + * expected type of a block is the anonymous class defined inside it. In that + * case there's technically a leak which is not removed by the ascription. */ - protected def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol], forcedDefined: Boolean = false)(implicit ctx: Context): Tree = { + protected def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(implicit ctx: Context): Tree = { def ascribeType(tree: Tree, pt: Type): Tree = tree match { case block @ Block(stats, expr) => val expr1 = ascribeType(expr, pt) @@ -640,16 +643,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case _ => Typed(tree, TypeTree(pt.simplified)) } - val leaks = escapingRefs(tree, localSyms) - if (leaks.isEmpty) tree - else if (isFullyDefined(pt, ForceDegree.none)) ascribeType(tree, pt) - else if (!forcedDefined) { + def noLeaks(t: Tree): Boolean = escapingRefs(t, localSyms).isEmpty + if (noLeaks(tree)) tree + else { fullyDefinedType(tree.tpe, "block", tree.pos) - val tree1 = ascribeType(tree, avoid(tree.tpe, localSyms)) - ensureNoLocalRefs(tree1, pt, localSyms, forcedDefined = true) - } else - errorTree(tree, - em"local definition of ${leaks.head.name} escapes as part of expression's type ${tree.tpe}"/*; full type: ${result.tpe.toString}"*/) + var avoidingType = avoid(tree.tpe, localSyms) + val ptDefined = isFullyDefined(pt, ForceDegree.none) + if (ptDefined && !(avoidingType <:< pt)) avoidingType = pt + val tree1 = ascribeType(tree, avoidingType) + assert(ptDefined || noLeaks(tree1), // `ptDefined` needed because of special case of anonymous classes + i"leak: ${escapingRefs(tree1, localSyms).toList}%, % in $tree1") + tree1 + } } def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): Tree = track("typedIf") { @@ -667,8 +672,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // this can type the greatest set of admissible closures. (pt.dealias.argTypesLo.init, pt.dealias.argTypesHi.last) case SAMType(meth) => - val mt @ MethodType(_, paramTypes) = meth.info - (paramTypes, mt.resultType) + val MethodTpe(_, formals, restpe) = meth.info + (formals, restpe) case _ => (List.range(0, defaultArity) map alwaysWildcardType, WildcardType) } @@ -1064,23 +1069,28 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } else { var args = tree.args - val args1 = - if (hasNamedArg(args)) typedNamedArgs(args) - else { - if (args.length != tparams.length) { - wrongNumberOfTypeArgs(tpt1.tpe, tparams, args, tree.pos) - args = args.take(tparams.length) - } - def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = { - val (desugaredArg, argPt) = - if (ctx.mode is Mode.Pattern) - (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramBounds) - else - (arg, WildcardType) - typed(desugaredArg, argPt) - } - args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]] + val args1 = { + if (args.length != tparams.length) { + wrongNumberOfTypeArgs(tpt1.tpe, tparams, args, tree.pos) + args = args.take(tparams.length) } + def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = { + val (desugaredArg, argPt) = + if (ctx.mode is Mode.Pattern) + (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramBounds) + else + (arg, WildcardType) + if (tpt1.symbol.isClass) + tparam match { + case tparam: Symbol => + // This is needed to get the test `compileParSetSubset` to work + tparam.ensureCompleted() + case _ => + } + typed(desugaredArg, argPt) + } + args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]] + } // check that arguments conform to bounds is done in phase PostTyper assignType(cpy.AppliedTypeTree(tree)(tpt1, args1), tpt1, args1) } @@ -1219,6 +1229,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit completeAnnotations(ddef, sym) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef]) + vparamss1.foreach(checkNoForwardDependencies) if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1) var tpt1 = checkSimpleKinded(typedType(tpt)) @@ -1277,10 +1288,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo match { case cinfo: PolyType => maybeCall(ref, psym, cinfo.resultType) - case cinfo @ MethodType(Nil, _) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => + case cinfo @ MethodType(Nil) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => val icall = New(ref).select(nme.CONSTRUCTOR).appliedToNone typedExpr(untpd.TypedSplice(icall))(superCtx) - case cinfo @ MethodType(Nil, _) if !cinfo.resultType.isInstanceOf[MethodType] => + case cinfo @ MethodType(Nil) if !cinfo.resultType.isInstanceOf[MethodType] => ref case cinfo: MethodType => if (!ctx.erasedTypes) { // after constructors arguments are passed in super call. @@ -1316,6 +1327,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible val dummy = localDummy(cls, impl) val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol)) + cls.setNoInitsFlags((NoInitsInterface /: body1)((fs, stat) => fs & defKind(stat))) // Expand comments and type usecases cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope) @@ -1715,7 +1727,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def tryInsertImplicitOnQualifier(tree: Tree, pt: Type)(implicit ctx: Context): Option[Tree] = ctx.traceIndented(i"try insert impl on qualifier $tree $pt") { tree match { case Select(qual, name) => - val qualProto = SelectionProto(name, pt, NoViewsAllowed) + val qualProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false) tryEither { implicit ctx => val qual1 = adaptInterpolated(qual, qualProto, EmptyTree) if ((qual eq qual1) || ctx.reporter.hasErrors) None @@ -2023,7 +2035,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // try an implicit conversion inferView(tree, pt) match { case SearchSuccess(inferred, _, _, _) => - adapt(inferred, pt) + adapt(inferred, pt)(ctx.retractMode(Mode.ImplicitsEnabled)) case failure: SearchFailure => if (pt.isInstanceOf[ProtoType] && !failure.isInstanceOf[AmbiguousImplicits]) tree else err.typeMismatch(tree, pt, failure) diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index 92bd9fd74..5a1745930 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -79,8 +79,8 @@ object Variances { varianceInType(parent)(tparam) & varianceInType(rinfo)(tparam) case tp: RecType => varianceInType(tp.parent)(tparam) - case tp @ MethodType(_, paramTypes) => - flip(varianceInTypes(paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam) + case tp: MethodType => + flip(varianceInTypes(tp.paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam) case ExprType(restpe) => varianceInType(restpe)(tparam) case tp @ HKApply(tycon, args) => diff --git a/compiler/src/dotty/tools/dotc/util/CommentParsing.scala b/compiler/src/dotty/tools/dotc/util/CommentParsing.scala index cc790d683..59b3c61b1 100644 --- a/compiler/src/dotty/tools/dotc/util/CommentParsing.scala +++ b/compiler/src/dotty/tools/dotc/util/CommentParsing.scala @@ -13,7 +13,7 @@ package dotty.tools.dotc.util * handled by dottydoc. */ object CommentParsing { - import scala.reflect.internal.Chars._ + import Chars._ /** Returns index of string `str` following `start` skipping longest * sequence of whitespace characters characters (but no newlines) diff --git a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala index 521947895..8892a570e 100644 --- a/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala +++ b/compiler/src/dotty/tools/dotc/util/FreshNameCreator.scala @@ -6,11 +6,6 @@ import scala.collection.mutable trait FreshNameCreator { def newName(prefix: String = ""): String - - @deprecated("use newName(prefix)", "2.9.0") - def newName(pos: scala.reflect.internal.util.Position, prefix: String): String = newName(prefix) - @deprecated("use newName()", "2.9.0") - def newName(pos: scala.reflect.internal.util.Position): String = newName() } object FreshNameCreator { diff --git a/compiler/src/dotty/tools/dotc/util/ShowPickled.scala b/compiler/src/dotty/tools/dotc/util/ShowPickled.scala index 477449074..3e06b3f91 100644 --- a/compiler/src/dotty/tools/dotc/util/ShowPickled.scala +++ b/compiler/src/dotty/tools/dotc/util/ShowPickled.scala @@ -5,13 +5,11 @@ import java.io.{File, FileInputStream, PrintStream} import java.lang.Long.toHexString import java.lang.Float.intBitsToFloat import java.lang.Double.longBitsToDouble -import scala.reflect.internal.Flags -import scala.reflect.internal.pickling.PickleFormat import core.unpickleScala2.PickleBuffer import core.Names._ object ShowPickled { - import PickleFormat._ + import core.unpickleScala2.PickleFormat._ case class PickleBufferEntry(num: Int, startIndex: Int, tag: Int, bytes: Array[Byte]) { def isName = tag == TERMname || tag == TYPEname diff --git a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala index aad4995d8..be5c46995 100644 --- a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala @@ -12,9 +12,14 @@ extends interfaces.SourcePosition { def lineContent: String = source.lineContent(point) def point: Int = pos.point + /** The line of the position, starting at 0 */ def line: Int = source.offsetToLine(point) + /** Extracts the lines from the underlying source file as `Array[Char]`*/ + def linesSlice: Array[Char] = + source.content.slice(source.startOfLine(start), source.nextLine(end)) + /** The lines of the position */ def lines: List[Int] = List.range(source.offsetToLine(start), source.offsetToLine(end + 1)) match { @@ -25,9 +30,6 @@ extends interfaces.SourcePosition { def lineOffsets: List[Int] = lines.map(source.lineToOffset(_)) - def lineContent(lineNumber: Int): String = - source.lineContent(source.lineToOffset(lineNumber)) - def beforeAndAfterPoint: (List[Int], List[Int]) = lineOffsets.partition(_ <= point) |