diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
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 } |