aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/typer
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala28
-rw-r--r--compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala9
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Inliner.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala22
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/typer/RefChecks.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala24
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala8
8 files changed, 71 insertions, 51 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 4e43e429b..c4d3e2292 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -20,6 +20,7 @@ import Trees._
import config.Config
import Names._
import StdNames._
+import NameKinds.DefaultGetterName
import ProtoTypes._
import EtaExpansion._
import Inferencing._
@@ -47,13 +48,15 @@ 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` is a subtype of the Product<numArgs> class.
+ * for a pattern with `numArgs` subpatterns?
+ * This is the case of `tp` has members `_1` to `_N` where `N == numArgs`.
*/
def isProductMatch(tp: Type, numArgs: Int)(implicit ctx: Context) =
- 0 <= numArgs && numArgs <= Definitions.MaxTupleArity &&
- tp.derivesFrom(defn.ProductNType(numArgs).typeSymbol)
+ numArgs > 0 && productArity(tp) == numArgs
/** Does `tp` fit the "get match" conditions as an unapply result type?
* This is the case of `tp` has a `get` member as well as a
@@ -68,6 +71,9 @@ object Applications {
sels.takeWhile(_.exists).toList
}
+ def productArity(tp: Type)(implicit ctx: Context) =
+ if (canProductMatch(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
sels.takeWhile(_.exists).toList
@@ -108,7 +114,7 @@ object Applications {
getUnapplySelectors(getTp, args, pos)
else if (unapplyResult isRef defn.BooleanClass)
Nil
- else if (defn.isProductSubType(unapplyResult))
+ else if (canProductMatch(unapplyResult))
productSelectorTypes(unapplyResult)
// this will cause a "wrong number of arguments in pattern" error later on,
// which is better than the message in `fail`.
@@ -345,7 +351,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
}
val getterPrefix =
if ((meth is Synthetic) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name
- def getterName = getterPrefix.defaultGetterName(n)
+ def getterName = DefaultGetterName(getterPrefix, n)
if (!meth.hasDefaultParams)
EmptyTree
else if (receiver.isEmpty) {
@@ -395,15 +401,14 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
def addTyped(arg: Arg, formal: Type): Type => Type = {
addArg(typedArg(arg, formal), formal)
if (methodType.isParamDependent)
- _.substParam(methodType.newParamRef(n), typeOfArg(arg))
- else
- identity
+ safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg))
+ else identity
}
def missingArg(n: Int): Unit = {
val pname = methodType.paramNames(n)
fail(
- if (pname contains '$') s"not enough arguments for $methString"
+ if (pname.firstPart contains '$') s"not enough arguments for $methString"
else s"missing argument for parameter $pname of $methString")
}
@@ -719,7 +724,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
val lhs1 = typedExpr(lhs)
val liftedDefs = new mutable.ListBuffer[Tree]
val lhs2 = untpd.TypedSplice(liftAssigned(liftedDefs, lhs1))
- val assign = untpd.Assign(lhs2, untpd.Apply(untpd.Select(lhs2, name.init), rhss))
+ val assign = untpd.Assign(lhs2,
+ untpd.Apply(untpd.Select(lhs2, name.asSimpleName.dropRight(1)), rhss))
wrapDefs(liftedDefs, typed(assign))
}
diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 5aee0fd54..e5480c98d 100644
--- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -12,6 +12,7 @@ import Symbols._
import Decorators._
import Names._
import StdNames._
+import NameKinds.UniqueName
import Trees._
import Inferencing._
import util.Positions._
@@ -21,10 +22,10 @@ object EtaExpansion {
import tpd._
- private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: String = "")(implicit ctx: Context): Tree =
+ private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: TermName = EmptyTermName)(implicit ctx: Context): Tree =
if (isPureExpr(expr)) expr
else {
- val name = ctx.freshName(prefix).toTermName
+ val name = UniqueName.fresh(prefix)
val liftedType = fullyDefinedType(expr.tpe.widen, "lifted expression", expr.pos)
val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, liftedType, coord = positionCoord(expr.pos))
defs += ValDef(sym, expr)
@@ -48,7 +49,7 @@ object EtaExpansion {
}
/** Lift a function argument, stripping any NamedArg wrapper */
- def liftArg(defs: mutable.ListBuffer[Tree], arg: Tree, prefix: String = "")(implicit ctx: Context): Tree =
+ def liftArg(defs: mutable.ListBuffer[Tree], arg: Tree, prefix: TermName = EmptyTermName)(implicit ctx: Context): Tree =
arg match {
case arg @ NamedArg(name, arg1) => cpy.NamedArg(arg)(name, lift(defs, arg1, prefix))
case arg => lift(defs, arg, prefix)
@@ -62,7 +63,7 @@ object EtaExpansion {
case mt: MethodType =>
(args, mt.paramNames, mt.paramInfos).zipped map { (arg, name, tp) =>
if (tp.isInstanceOf[ExprType]) arg
- else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$")
+ else liftArg(defs, arg, if (name.firstPart contains '$') EmptyTermName else name)
}
case _ =>
args map (liftArg(defs, _))
diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala
index f6d65fbb9..38a139be1 100644
--- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala
@@ -13,8 +13,9 @@ import Decorators._
import Constants._
import StdNames.nme
import Contexts.Context
-import Names.{Name, TermName}
+import Names.{Name, TermName, EmptyTermName}
import NameOps._
+import NameKinds.{InlineAccessorName, OuterSelectName}
import SymDenotations.SymDenotation
import Annotations._
import transform.ExplicitOuter
@@ -49,8 +50,7 @@ object Inliner {
sym.is(AccessFlags) || sym.privateWithin.exists
/** The name of the next accessor to be generated */
- def accessorName(implicit ctx: Context) =
- ctx.freshNames.newName(inlineMethod.name.asTermName.inlineAccessorName.toString)
+ def accessorName(implicit ctx: Context) = InlineAccessorName.fresh(inlineMethod.name.asTermName)
/** A fresh accessor symbol.
*
@@ -399,9 +399,6 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
// The class that the this-proxy `selfSym` represents
def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol
- // The name of the outer selector that computes the rhs of `selfSym`
- def outerSelector(n: Int): TermName = n.toString.toTermName ++ nme.OUTER_SELECT
-
// The total nesting depth of the class represented by `selfSym`.
def outerLevel(selfSym: Symbol): Int = classOf(selfSym).ownersIterator.length
@@ -419,7 +416,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
if (!lastSelf.exists)
prefix
else
- untpd.Select(ref(lastSelf), outerSelector(lastLevel - level)).withType(selfSym.info)
+ untpd.Select(ref(lastSelf), OuterSelectName(EmptyTermName, lastLevel - level)).withType(selfSym.info)
bindingsBuf += ValDef(selfSym.asTerm, rhs)
lastSelf = selfSym
lastLevel = level
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index ce2030c01..da9f9f6ac 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -6,6 +6,7 @@ import core._
import ast._
import Trees._, Constants._, StdNames._, Scopes._, Denotations._, Comments._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
+import NameKinds.DefaultGetterName
import ast.desugar, ast.desugar._
import ProtoTypes._
import util.Positions._
@@ -281,7 +282,7 @@ class Namer { typer: Typer =>
tree match {
case tree: TypeDef if tree.isClassDef =>
- val name = checkNoConflict(tree.name.encode).asTypeName
+ val name = checkNoConflict(tree.name.encode).toTypeName
val flags = checkFlags(tree.mods.flags &~ Implicit)
val cls = recordSym(ctx.newClassSymbol(
ctx.owner, name, flags | inSuperCall,
@@ -842,7 +843,7 @@ class Namer { typer: Typer =>
val targs1 = targs map (typedAheadType(_))
val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes
if (ptype.typeParams.isEmpty) ptype
- else typedAheadExpr(parent).tpe
+ else fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos)
}
/* Check parent type tree `parent` for the following well-formedness conditions:
@@ -1012,12 +1013,8 @@ class Namer { typer: Typer =>
* the corresponding parameter where bound parameters are replaced by
* Wildcards.
*/
- def rhsProto = {
- val name = sym.asTerm.name
- val idx = name.defaultGetterIndex
- if (idx < 0) WildcardType
- else {
- val original = name.defaultGetterToMethod
+ def rhsProto = sym.asTerm.name collect {
+ case DefaultGetterName(original, idx) =>
val meth: Denotation =
if (original.isConstructorName && (sym.owner is ModuleClass))
sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
@@ -1035,17 +1032,18 @@ class Namer { typer: Typer =>
paramProto(defaultAlts.head.info.widen.paramInfoss, idx)
else
WildcardType
- }
- }
+ } getOrElse WildcardType
// println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
def isInline = sym.is(FinalOrInline, butNot = Method | Mutable)
// Widen rhs type and approximate `|' but keep ConstantTypes if
- // definition is inline (i.e. final in Scala2).
+ // definition is inline (i.e. final in Scala2) and keep module singleton types
+ // instead of widening to the underlying module class types.
def widenRhs(tp: Type): Type = tp.widenTermRefExpr match {
- case tp: ConstantType if isInline => tp
+ case ctp: ConstantType if isInline => ctp
+ case ref: TypeRef if ref.symbol.is(ModuleClass) => tp
case _ => ctx.harmonizeUnion(tp.widen)
}
diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
index ab342dc17..398a7a17e 100644
--- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -5,6 +5,7 @@ package typer
import core._
import ast._
import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
+import NameKinds.DepParamName
import Trees._
import Constants._
import Scopes._
@@ -401,7 +402,7 @@ object ProtoTypes {
/** Create a new TypeParamRef that represents a dependent method parameter singleton */
def newDepTypeParamRef(tp: Type)(implicit ctx: Context): TypeParamRef = {
- val poly = PolyType(ctx.freshName(nme.DEP_PARAM_PREFIX).toTypeName :: Nil)(
+ val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)(
pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil,
pt => defn.AnyType)
ctx.typeComparer.addToConstraint(poly, Nil)
diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
index d61f5fa68..4715873e5 100644
--- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -6,6 +6,7 @@ import core._
import config._
import Symbols._, SymDenotations._, Types._, Contexts._, Decorators._, Flags._, Names._, NameOps._
import StdNames._, Denotations._, Scopes._, Constants.Constant, SymUtils._
+import NameKinds.DefaultGetterName
import Annotations._
import util.Positions._
import scala.collection.{ mutable, immutable }
@@ -24,12 +25,8 @@ object RefChecks {
import reporting.diagnostic.Message
import reporting.diagnostic.messages._
-
- private def isDefaultGetter(name: Name): Boolean =
- name.isTermName && name.asTermName.defaultGetterIndex >= 0
-
private val defaultMethodFilter = new NameFilter {
- def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = isDefaultGetter(name)
+ def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = name.is(DefaultGetterName)
}
/** Only one overloaded alternative is allowed to define default arguments */
@@ -45,7 +42,9 @@ object RefChecks {
if defaultGetterClass.isClass
) {
val defaultGetterNames = defaultGetterClass.asClass.memberNames(defaultMethodFilter)
- val defaultMethodNames = defaultGetterNames map (_.asTermName.defaultGetterToMethod)
+ val defaultMethodNames = defaultGetterNames map { _ rewrite {
+ case DefaultGetterName(methName, _) => methName
+ }}
for (name <- defaultMethodNames) {
val methods = clazz.info.member(name).alternatives.map(_.symbol)
@@ -238,7 +237,7 @@ object RefChecks {
}
}
else
- isDefaultGetter(member.name) || // default getters are not checked for compatibility
+ member.name.is(DefaultGetterName) || // default getters are not checked for compatibility
memberTp.overrides(otherTp)
//Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
@@ -298,7 +297,7 @@ object RefChecks {
} else if (other.isEffectivelyFinal) { // (1.2)
overrideError(i"cannot override final member ${other.showLocated}")
} else if (!other.is(Deferred) &&
- !isDefaultGetter(other.name) &&
+ !other.name.is(DefaultGetterName) &&
!member.isAnyOverride) {
// (*) Exclusion for default getters, fixes SI-5178. We cannot assign the Override flag to
// the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket.
@@ -405,7 +404,7 @@ object RefChecks {
def ignoreDeferred(member: SingleDenotation) =
member.isType ||
- member.symbol.is(SuperAccessor) || // not yet synthesized
+ member.symbol.isSuperAccessor || // not yet synthesized
member.symbol.is(JavaDefined) && hasJavaErasedOverriding(member.symbol)
// 2. Check that only abstract classes have deferred members
diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 2aa7036b4..ec6fb1770 100644
--- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -91,8 +91,8 @@ trait TypeAssigner {
else
parent
}
- val refinableDecls = info.decls.filterNot(
- sym => sym.is(TypeParamAccessor | Private) || sym.isConstructor)
+ val refinableDecls = info.decls.filter(
+ sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor))
val fullType = (parentType /: refinableDecls)(addRefinement)
mapOver(fullType)
case TypeBounds(lo, hi) if variance > 0 =>
@@ -315,10 +315,28 @@ trait TypeAssigner {
}
}
+ /** Substitute argument type `argType` for parameter `pref` in type `tp`,
+ * skolemizing the argument type if it is not stable and `pref` occurs in `tp`.
+ */
+ def safeSubstParam(tp: Type, pref: ParamRef, argType: Type)(implicit ctx: Context) = {
+ val tp1 = tp.substParam(pref, argType)
+ if ((tp1 eq tp) || argType.isStable) tp1
+ else tp.substParam(pref, SkolemType(argType.widen))
+ }
+
def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
val ownType = fn.tpe.widen match {
case fntpe: MethodType =>
- if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
+ def safeSubstParams(tp: Type, params: List[ParamRef], args: List[Tree]): Type = params match {
+ case param :: params1 =>
+ val tp1 = safeSubstParam(tp, param, args.head.tpe)
+ safeSubstParams(tp1, params1, args.tail)
+ case Nil =>
+ tp
+ }
+ if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping)
+ if (fntpe.isDependent) safeSubstParams(fntpe.resultType, fntpe.paramRefs, args)
+ else fntpe.resultType
else
errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.pos)
case t =>
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 8a124b17b..4bf938fd4 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -18,6 +18,7 @@ import SymDenotations._
import Annotations._
import Names._
import NameOps._
+import NameKinds._
import Flags._
import Decorators._
import ErrorReporting._
@@ -568,7 +569,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def canAssign(sym: Symbol) = // allow assignments from the primary constructor to class fields
sym.is(Mutable, butNot = Accessor) ||
ctx.owner.isPrimaryConstructor && !sym.is(Method) && sym.owner == ctx.owner.owner ||
- ctx.owner.name.isTraitSetterName || ctx.owner.isStaticConstructor
+ ctx.owner.name.is(TraitSetterName) || ctx.owner.isStaticConstructor
lhsCore.tpe match {
case ref: TermRef if canAssign(ref.symbol) =>
assignType(cpy.Assign(tree)(lhs1, typed(tree.rhs, ref.info)))
@@ -757,10 +758,9 @@ 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) = {
- val pclass = defn.ProductNType(params.length).symbol
isFullyDefined(formal, ForceDegree.noBottom) &&
- formal.derivesFrom(pclass) &&
- formal.baseArgTypes(pclass).corresponds(params) {
+ Applications.canProductMatch(formal) &&
+ Applications.productSelectorTypes(formal).corresponds(params) {
(argType, param) =>
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe
}