diff options
Diffstat (limited to 'compiler/src/dotty/tools')
9 files changed, 49 insertions, 28 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index a97589d73..eee6ba785 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 typer.Applications object Definitions { @@ -846,6 +845,9 @@ class Definitions { TupleType(elems.size).appliedTo(elems) } + def isProductSubType(tp: Type)(implicit ctx: Context) = + tp.derivesFrom(ProductType.symbol) + /** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN? */ def isFunctionType(tp: Type)(implicit ctx: Context) = { val arity = functionArity(tp) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 0f08e4701..81ac3a02f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -209,7 +209,7 @@ object NameKinds { val InlineAccessorName = new UniqueNameKind("$_inlineAccessor_$") val TempResultName = new UniqueNameKind("ev$") val EvidenceParamName = new UniqueNameKind("evidence$") - val DepParamName = new UniqueNameKind("<param>") + val DepParamName = new UniqueNameKind("(param)") val LazyImplicitName = new UniqueNameKind("$_lazy_implicit_$") val LazyLocalName = new UniqueNameKind("$lzy") val LazyLocalInitName = new UniqueNameKind("$lzyINIT") diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 9593bfe93..4a1c3d044 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -7,6 +7,7 @@ import SymDenotations._, Denotations.SingleDenotation import config.Printers.typr import util.Positions._ import NameOps._ +import NameKinds.DepParamName import Decorators._ import StdNames._ import Annotations._ @@ -158,7 +159,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object. case tp1 => tp1 } case tp: TypeParamRef => - typerState.constraint.typeVarOfParam(tp) orElse tp + if (tp.paramName.is(DepParamName)) { + val bounds = ctx.typeComparer.bounds(tp) + if (bounds.lo.isRef(defn.NothingClass)) bounds.hi else bounds.lo + } + else typerState.constraint.typeVarOfParam(tp) orElse tp case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c8c1886cc..955a5a11c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3509,7 +3509,7 @@ object Types { def apply(tp: Type): Type - protected var variance = 1 + protected[core] var variance = 1 protected def derivedSelect(tp: NamedType, pre: Type): Type = tp.derivedSelect(pre) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 26c823f97..9415c047f 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -7,7 +7,7 @@ import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._ import NameKinds.{ModuleClassName, DefaultGetterName} import ast.tpd._ -import java.io.{ File, IOException } +import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException } import java.lang.Integer.toHexString import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, ArrayBuffer } @@ -194,13 +194,21 @@ class ClassfileParser( val name = pool.getName(in.nextChar) val isConstructor = name eq nme.CONSTRUCTOR - /** Strip leading outer param from constructor. - * Todo: Also strip trailing access tag for private inner constructors? + /** Strip leading outer param from constructor and trailing access tag for + * private inner constructors. */ - def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match { + def normalizeConstructorParams() = innerClasses.get(currentClassName) match { case Some(entry) if !isStatic(entry.jflags) => val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info - denot.info = mt.derivedLambdaType(paramNames.tail, paramTypes.tail, resultType) + var normalizedParamNames = paramNames.tail + var normalizedParamTypes = paramTypes.tail + if ((jflags & JAVA_ACC_SYNTHETIC) != 0) { + // SI-7455 strip trailing dummy argument ("access constructor tag") from synthetic constructors which + // are added when an inner class needs to access a private constructor. + normalizedParamNames = paramNames.dropRight(1) + normalizedParamTypes = paramTypes.dropRight(1) + } + denot.info = mt.derivedLambdaType(normalizedParamNames, normalizedParamTypes, resultType) case _ => } @@ -216,7 +224,7 @@ class ClassfileParser( denot.info = pool.getType(in.nextChar) if (isEnum) denot.info = ConstantType(Constant(sym)) - if (isConstructor) stripOuterParamFromConstructor() + if (isConstructor) normalizeConstructorParams() setPrivateWithin(denot, jflags) denot.info = translateTempPoly(parseAttributes(sym, denot.info)) if (isConstructor) normalizeConstructorInfo() @@ -227,8 +235,12 @@ class ClassfileParser( // seal java enums if (isEnum) { val enumClass = sym.owner.linkedClass - if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed) - enumClass.addAnnotation(Annotation.makeChild(sym)) + if (!enumClass.exists) + ctx.warning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.") + else { + if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed) + enumClass.addAnnotation(Annotation.makeChild(sym)) + } } } finally { in.bp = oldbp @@ -923,12 +935,16 @@ class ClassfileParser( case null => val start = starts(index) if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) - val name = termName(in.buf, start + 3, in.getChar(start + 1)) + val len = in.getChar(start + 1).toInt + val name = termName(fromMUTF8(in.buf, start + 1, len + 2)) values(index) = name name } } + private def fromMUTF8(bytes: Array[Byte], offset: Int, len: Int): String = + new DataInputStream(new ByteArrayInputStream(bytes, offset, len)).readUTF + /** Return the name found at given index in the constant pool, with '/' replaced by '.'. */ def getExternalName(index: Int): SimpleTermName = { if (index <= 0 || len <= index) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 41a1218eb..447a003e7 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -1408,7 +1408,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { protected def seqTree(binder: Symbol) = tupleSel(binder)(firstIndexingBinder + 1) protected def tupleSel(binder: Symbol)(i: Int): Tree = { val accessors = - if (Applications.canProductMatch(binder.info)) + if (defn.isProductSubType(binder.info)) productSelectors(binder.info) else binder.caseAccessors val res = diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index c4d3e2292..7e17abbcd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -48,9 +48,6 @@ object Applications { ref.info.widenExpr.dealias } - def canProductMatch(tp: Type)(implicit ctx: Context) = - extractorMemberType(tp, nme._1).exists - /** Does `tp` fit the "product match" conditions as an unapply result type * for a pattern with `numArgs` subpatterns? * This is the case of `tp` has members `_1` to `_N` where `N == numArgs`. @@ -72,7 +69,7 @@ object Applications { } def productArity(tp: Type)(implicit ctx: Context) = - if (canProductMatch(tp)) productSelectorTypes(tp).size else -1 + if (defn.isProductSubType(tp)) productSelectorTypes(tp).size else -1 def productSelectors(tp: Type)(implicit ctx: Context): List[Symbol] = { val sels = for (n <- Iterator.from(0)) yield tp.member(nme.selectorName(n)).symbol @@ -114,7 +111,7 @@ object Applications { getUnapplySelectors(getTp, args, pos) else if (unapplyResult isRef defn.BooleanClass) Nil - else if (canProductMatch(unapplyResult)) + else if (defn.isProductSubType(unapplyResult)) productSelectorTypes(unapplyResult) // this will cause a "wrong number of arguments in pattern" error later on, // which is better than the message in `fail`. diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 398a7a17e..5d8240362 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -377,9 +377,10 @@ object ProtoTypes { * Also, if `owningTree` is non-empty, add a type variable for each parameter. * @return The added type lambda, and the list of created type variables. */ - def constrained(tl: TypeLambda, owningTree: untpd.Tree)(implicit ctx: Context): (TypeLambda, List[TypeTree]) = { + def constrained(tl: TypeLambda, owningTree: untpd.Tree, alwaysAddTypeVars: Boolean = false)(implicit ctx: Context): (TypeLambda, List[TypeTree]) = { val state = ctx.typerState - assert(!(ctx.typerState.isCommittable && owningTree.isEmpty), + val addTypeVars = alwaysAddTypeVars || !owningTree.isEmpty + assert(!(ctx.typerState.isCommittable && !addTypeVars), s"inconsistent: no typevars were added to committable constraint ${state.constraint}") def newTypeVars(tl: TypeLambda): List[TypeTree] = @@ -392,7 +393,7 @@ object ProtoTypes { val added = if (state.constraint contains tl) tl.newLikeThis(tl.paramNames, tl.paramInfos, tl.resultType) else tl - val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added) + val tvars = if (addTypeVars) newTypeVars(added) else Nil ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]]) (added, tvars) } @@ -400,13 +401,13 @@ object ProtoTypes { /** Same as `constrained(tl, EmptyTree)`, but returns just the created type lambda */ def constrained(tl: TypeLambda)(implicit ctx: Context): TypeLambda = constrained(tl, EmptyTree)._1 - /** Create a new TypeParamRef that represents a dependent method parameter singleton */ - def newDepTypeParamRef(tp: Type)(implicit ctx: Context): TypeParamRef = { + /** Create a new TypeVar that represents a dependent method parameter singleton */ + def newDepTypeVar(tp: Type)(implicit ctx: Context): TypeVar = { val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)( pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil, pt => defn.AnyType) - ctx.typeComparer.addToConstraint(poly, Nil) - TypeParamRef(poly, 0) + constrained(poly, untpd.EmptyTree, alwaysAddTypeVars = true) + ._2.head.tpe.asInstanceOf[TypeVar] } /** The result type of `mt`, where all references to parameters of `mt` are @@ -415,7 +416,7 @@ object ProtoTypes { def resultTypeApprox(mt: MethodType)(implicit ctx: Context): Type = if (mt.isDependent) { def replacement(tp: Type) = - if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeParamRef(tp) + if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeVar(tp) mt.resultType.substParams(mt, mt.paramInfos.map(replacement)) } else mt.resultType diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 4bf938fd4..02538671e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -759,7 +759,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit /** Is `formal` a product type which is elementwise compatible with `params`? */ def ptIsCorrectProduct(formal: Type) = { isFullyDefined(formal, ForceDegree.noBottom) && - Applications.canProductMatch(formal) && + defn.isProductSubType(formal) && Applications.productSelectorTypes(formal).corresponds(params) { (argType, param) => param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe |