diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2014-02-16 16:58:28 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-02-16 19:25:38 +0100 |
commit | 862f7709cdabd82327ca0f37a480884c88f96be7 (patch) | |
tree | 688717816eeee19ddb391f1009c82d9b6f09f224 /src/reflect | |
parent | 2fc0164a5e777a0495c1801d8d38d60158ec2a77 (diff) | |
parent | 6ef6c96eff2f0d2f505d45a1436d73a960193076 (diff) | |
download | scala-862f7709cdabd82327ca0f37a480884c88f96be7.tar.gz scala-862f7709cdabd82327ca0f37a480884c88f96be7.tar.bz2 scala-862f7709cdabd82327ca0f37a480884c88f96be7.zip |
Merge remote-tracking branch 'origin/master' into topic/palladium0
Conflicts:
src/compiler/scala/reflect/macros/compiler/Resolvers.scala
src/compiler/scala/reflect/macros/contexts/Typers.scala
src/compiler/scala/tools/reflect/ToolBoxFactory.scala
src/reflect/scala/reflect/api/BuildUtils.scala
Diffstat (limited to 'src/reflect')
13 files changed, 210 insertions, 103 deletions
diff --git a/src/reflect/scala/reflect/api/Internals.scala b/src/reflect/scala/reflect/api/Internals.scala index 2fd52d5cd8..37406385c8 100644 --- a/src/reflect/scala/reflect/api/Internals.scala +++ b/src/reflect/scala/reflect/api/Internals.scala @@ -698,6 +698,12 @@ trait Internals { self: Universe => def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] } + val SyntacticPatDef: SyntacticPatDefExtractor + + trait SyntacticPatDefExtractor { + def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef] + } + val SyntacticAssign: SyntacticAssignExtractor trait SyntacticAssignExtractor { diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index 6f634c55fe..b262fdce68 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -142,6 +142,7 @@ trait Printers { self: Universe => def print(args: Any*) protected var printTypes = false protected var printIds = false + protected var printOwners = false protected var printKinds = false protected var printMirrors = false protected var printPositions = false @@ -149,6 +150,8 @@ trait Printers { self: Universe => def withoutTypes: this.type = { printTypes = false; this } def withIds: this.type = { printIds = true; this } def withoutIds: this.type = { printIds = false; this } + def withOwners: this.type = { printOwners = true; this } + def withoutOwners: this.type = { printOwners = false; this } def withKinds: this.type = { printKinds = true; this } def withoutKinds: this.type = { printKinds = false; this } def withMirrors: this.type = { printMirrors = true; this } @@ -169,12 +172,13 @@ trait Printers { self: Universe => } /** @group Printers */ - protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = { + protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = { val buffer = new StringWriter() val writer = new PrintWriter(buffer) val printer = mkPrinter(writer) printTypes.value.map(printTypes => if (printTypes) printer.withTypes else printer.withoutTypes) printIds.value.map(printIds => if (printIds) printer.withIds else printer.withoutIds) + printOwners.value.map(printOwners => if (printOwners) printer.withOwners else printer.withoutOwners) printKinds.value.map(printKinds => if (printKinds) printer.withKinds else printer.withoutKinds) printMirrors.value.map(printMirrors => if (printMirrors) printer.withMirrors else printer.withoutMirrors) printPositions.value.map(printPositions => if (printPositions) printer.withPositions else printer.withoutPositions) @@ -193,8 +197,8 @@ trait Printers { self: Universe => * * @group Printers */ - def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = - render(any, newTreePrinter(_), printTypes, printIds, printKinds, printMirrors, printPositions) + def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = + render(any, newTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions) /** Hook to define what `show(...)` means. * @group Printers @@ -225,8 +229,8 @@ trait Printers { self: Universe => * * @group Printers */ - def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = - render(any, newRawTreePrinter(_), printTypes, printIds, printKinds, printMirrors, printPositions) + def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = + render(any, newRawTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions) /** Hook to define what `showRaw(...)` means. * @group Printers diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 6fc00de3e5..af11de46ce 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -54,9 +54,6 @@ trait StandardLiftables { self: Universe => case right: Right[L, R] => lift(right) } - implicit def liftTuple1[T1](implicit liftT1: Liftable[T1]): Liftable[Tuple1[T1]] = Liftable { t => - SyntacticTuple(liftT1(t._1) :: Nil) - } implicit def liftTuple2[T1, T2](implicit liftT1: Liftable[T1], liftT2: Liftable[T2]): Liftable[Tuple2[T1, T2]] = Liftable { t => SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: Nil) } @@ -148,9 +145,6 @@ trait StandardLiftables { self: Universe => implicit def unliftType: Unliftable[Type] = Unliftable[Type] { case tt: TypeTree if tt.tpe != null => tt.tpe } implicit def unliftConstant: Unliftable[Constant] = Unliftable[Constant] { case Literal(const) => const } - implicit def unliftTuple1[T1](implicit UnliftT1: Unliftable[T1]): Unliftable[Tuple1[T1]] = Unliftable { - case SyntacticTuple(UnliftT1(v1) :: Nil) => Tuple1(v1) - } implicit def unliftTuple2[T1, T2](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2]): Unliftable[Tuple2[T1, T2]] = Unliftable { case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: Nil) => Tuple2(v1, v2) } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 8ec4c98cd9..b1d76b6056 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -33,10 +33,10 @@ trait Printers extends api.Printers { self: SymbolTable => def qowner = quotedName(sym.owner.name.dropLocal, decoded) def qsymbol = quotedName(sym.nameString) - if (sym.name.toTermName == nme.ERROR) - s"<$qname: error>" - else if (sym == null || sym == NoSymbol) + if (sym == null || sym == NoSymbol) qname + else if (sym.isErroneous) + s"<$qname: error>" else if (sym.isMixinConstructor) s"/*$qowner*/$qsymbol" else @@ -65,6 +65,7 @@ trait Printers extends api.Printers { self: SymbolTable => printTypes = settings.printtypes.value printIds = settings.uniqid.value + printOwners = settings.Yshowsymowners.value printKinds = settings.Yshowsymkinds.value printMirrors = false // typically there's no point to print mirrors inside the compiler, as there is only one mirror there printPositions = settings.Xprintpos.value @@ -275,6 +276,7 @@ trait Printers extends api.Printers { self: SymbolTable => printValueParams print(" => ", body, ")") if (printIds && tree.symbol != null) print("#" + tree.symbol.id) + if (printOwners && tree.symbol != null) print("@" + tree.symbol.owner.id) } protected def printSuper(tree: Super, resultName: => String) = { @@ -1093,7 +1095,7 @@ trait Printers extends api.Printers { self: SymbolTable => case self.pendingSuperCall => print("pendingSuperCall") case tree: Tree => - val hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol + def hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol val isError = hasSymbolField && (tree.symbol.name string_== nme.ERROR) printProduct( tree, @@ -1139,6 +1141,7 @@ trait Printers extends api.Printers { self: SymbolTable => else if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName) else print(sym.name) if (printIds) print("#", sym.id) + if (printOwners) print("@", sym.owner.id) if (printKinds) print("#", sym.abbreviatedKindString) if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym))) case tag: TypeTag[_] => diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index 6a91109faf..087d4186be 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -226,9 +226,9 @@ trait ReificationSupport { self: SymbolTable => // recover constructor contents generated by gen.mkTemplate protected object UnCtor { def unapply(tree: Tree): Option[(Modifiers, List[List[ValDef]], List[Tree])] = tree match { - case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, Block(lvdefs, _)) => + case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, SyntacticBlock(lvdefs :+ _)) => Some((mods | Flag.TRAIT, Nil, lvdefs)) - case DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, _, Block(lvdefs :+ _, _)) => + case DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, _, SyntacticBlock(lvdefs :+ _ :+ _)) => Some((mods, vparamss, lvdefs)) case _ => None } @@ -383,7 +383,7 @@ trait ReificationSupport { self: SymbolTable => object SyntacticTuple extends SyntacticTupleExtractor { def apply(args: List[Tree]): Tree = { require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported") - gen.mkTuple(args, flattenUnary = false) + gen.mkTuple(args) } def unapply(tree: Tree): Option[List[Tree]] = tree match { @@ -393,6 +393,8 @@ trait ReificationSupport { self: SymbolTable => if sym == TupleClass(args.length).companionModule && (targs.isEmpty || targs.length == args.length) => Some(args) + case _ if tree.isTerm => + Some(tree :: Nil) case _ => None } @@ -401,7 +403,7 @@ trait ReificationSupport { self: SymbolTable => object SyntacticTupleType extends SyntacticTupleExtractor { def apply(args: List[Tree]): Tree = { require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported") - gen.mkTupleType(args, flattenUnary = false) + gen.mkTupleType(args) } def unapply(tree: Tree): Option[List[Tree]] = tree match { @@ -410,6 +412,8 @@ trait ReificationSupport { self: SymbolTable => case MaybeTypeTreeOriginal(AppliedTypeTree(TupleClassRef(sym), args)) if sym == TupleClass(args.length) => Some(args) + case _ if tree.isType => + Some(tree :: Nil) case _ => None } @@ -507,10 +511,9 @@ trait ReificationSupport { self: SymbolTable => } protected class SyntacticValDefBase(isMutable: Boolean) extends SyntacticValDefExtractor { - def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) = { - val mods1 = if (isMutable) mods | MUTABLE else mods - ValDef(mods1, name, tpt, rhs) - } + def modifiers(mods: Modifiers): Modifiers = if (isMutable) mods | MUTABLE else mods + + def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef = ValDef(modifiers(mods), name, tpt, rhs) def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] = tree match { case ValDef(mods, name, tpt, rhs) if mods.hasFlag(MUTABLE) == isMutable => @@ -580,25 +583,57 @@ trait ReificationSupport { self: SymbolTable => // match a sequence of desugared `val $pat = $value` protected object UnPatSeq { - def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = trees match { - case Nil => Some(Nil) - // case q"$mods val ${_}: ${_} = ${MaybeUnchecked(value)} match { case $pat => (..$ids) }" :: tail - case ValDef(mods, _, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail + def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = { + val imploded = implodePatDefs(trees) + val patvalues = imploded.flatMap { + case SyntacticPatDef(_, pat, EmptyTree, rhs) => Some((pat, rhs)) + case ValDef(_, name, SyntacticEmptyTypeTree(), rhs) => Some((Bind(name, self.Ident(nme.WILDCARD)), rhs)) + case ValDef(_, name, tpt, rhs) => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), rhs)) + case _ => None + } + if (patvalues.length == imploded.length) Some(patvalues) else None + } + } + + // implode multiple-statement desugaring of pattern definitions + // into single-statement valdefs with nme.QUASIQUOTE_PAT_DEF name + object implodePatDefs extends Transformer { + override def transform(tree: Tree) = tree match { + case templ: Template => deriveTemplate(templ)(transformStats) + case block: Block => + val Block(init, last) = block + Block(transformStats(init), transform(last)).copyAttrs(block) + case ValDef(mods, name1, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil)) + if name1 == name2 => + ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) + case _ => + super.transform(tree) + } + def transformStats(trees: List[Tree]): List[Tree] = trees match { + case Nil => Nil + case ValDef(mods, _, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail if mods.hasFlag(SYNTHETIC) && mods.hasFlag(ARTIFACT) => - tail.drop(ids.length) match { - case UnPatSeq(rest) => Some((pat, value) :: rest) - case _ => None + ids match { + case Nil => + ValDef(NoMods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail) + case _ => + val mods = tail.take(1).head.asInstanceOf[ValDef].mods + ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail.drop(ids.length)) } - // case q"${_} val $name1: ${_} = ${MaybeUnchecked(value)} match { case $pat => ${Ident(name2)} }" :: UnPatSeq(rest) - case ValDef(_, name1, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil)) :: UnPatSeq(rest) - if name1 == name2 => - Some((pat, value) :: rest) - // case q"${_} val $name: ${SyntacticEmptyTypeTree()} = $value" :: UnPatSeq(rest) => - case ValDef(_, name, SyntacticEmptyTypeTree(), value) :: UnPatSeq(rest) => - Some((Bind(name, self.Ident(nme.WILDCARD)), value) :: rest) - // case q"${_} val $name: $tpt = $value" :: UnPatSeq(rest) => - case ValDef(_, name, tpt, value) :: UnPatSeq(rest) => - Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), value) :: rest) + case other :: tail => + transform(other) :: transformStats(tail) + } + def apply(tree: Tree) = transform(tree) + def apply(trees: List[Tree]) = transformStats(trees) + } + + object SyntacticPatDef extends SyntacticPatDefExtractor { + def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef] = tpt match { + case SyntacticEmptyTypeTree() => gen.mkPatDef(mods, pat, rhs) + case _ => gen.mkPatDef(mods, Typed(pat, tpt), rhs) + } + def unapply(tree: Tree): Option[(Modifiers, Tree, Tree, Tree)] = tree match { + case ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), rhs) => Some((mods, pat, tpt, rhs)) case _ => None } } @@ -779,6 +814,13 @@ trait ReificationSupport { self: SymbolTable => } } + protected object MaybeTyped { + def unapply(tree: Tree): Some[(Tree, Tree)] = tree match { + case Typed(v, tpt) => Some((v, tpt)) + case v => Some((v, SyntacticEmptyTypeTree())) + } + } + protected def mkCases(cases: List[Tree]): List[CaseDef] = cases.map { case c: CaseDef => c case tree => throw new IllegalArgumentException("$tree is not valid representation of pattern match case") diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 1e133eced9..b95c83d6cb 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -253,12 +253,8 @@ trait StdNames { final val Quasiquote: NameType = "Quasiquote" // quasiquote-specific names - final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$" final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" - final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$" - final val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$" - final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" // Annotation simple names, used in Namer @@ -312,6 +308,8 @@ trait StdNames { val WHILE_PREFIX = "while$" val FRESH_PREFIX = "fresh" val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names + val QUAL_PREFIX = "qual$" + val NAMEDARG_PREFIX = "x$" // Compiler internal names val ANYname: NameType = "<anyname>" @@ -331,12 +329,17 @@ trait StdNames { val REIFY_FREE_THIS_SUFFIX: NameType = "$this" val REIFY_FREE_VALUE_SUFFIX: NameType = "$value" val REIFY_SYMDEF_PREFIX: NameType = "symdef$" - val QUASIQUOTE_PREFIX: String = "qq$" - val QUASIQUOTE_NAME_PREFIX: String = "nn$" - val QUASIQUOTE_FILE: String = "<quasiquote>" - val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" val QUASIQUOTE_CASE: NameType = "$quasiquote$case$" + val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$" + val QUASIQUOTE_FILE: String = "<quasiquote>" val QUASIQUOTE_FOR_ENUM: NameType = "$quasiquote$for$enum$" + val QUASIQUOTE_NAME_PREFIX: String = "nn$" + val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$" + val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$" + val QUASIQUOTE_PAT_DEF: NameType = "$quasiquote$pat$def$" + val QUASIQUOTE_PREFIX: String = "qq$" + val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" + val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" val QUASIQUOTE_UNLIFT_HELPER: String = "$quasiquote$unlift$helper$" val MIXIN_CONSTRUCTOR: NameType = "$init$" val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" @@ -625,6 +628,7 @@ trait StdNames { val SyntacticNew: NameType = "SyntacticNew" val SyntacticObjectDef: NameType = "SyntacticObjectDef" val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef" + val SyntacticPatDef: NameType = "SyntacticPatDef" val SyntacticTraitDef: NameType = "SyntacticTraitDef" val SyntacticTry: NameType = "SyntacticTry" val SyntacticTuple: NameType = "SyntacticTuple" @@ -651,7 +655,6 @@ trait StdNames { val applyDynamicNamed: NameType = "applyDynamicNamed" val applyOrElse: NameType = "applyOrElse" val args : NameType = "args" - val argv : NameType = "argv" val arrayClass: NameType = "arrayClass" val array_apply : NameType = "array_apply" val array_clone : NameType = "array_clone" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 5e81badfad..5fa4772d60 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -405,9 +405,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Create a new existential type skolem with this symbol its owner, * based on the given symbol and origin. */ - def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = { - val skolem = newTypeSkolemSymbol(basis.name.toTypeName, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM) - skolem setInfo (basis.info cloneInfo skolem) + def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = + newExistentialSkolem(basis.name.toTypeName, basis.info, basis.flags, basis.pos, origin) + + /** Create a new existential type skolem with this symbol its owner, and the given other properties. + */ + def newExistentialSkolem(name: TypeName, info: Type, flags: Long, pos: Position, origin: AnyRef): TypeSkolem = { + val skolem = newTypeSkolemSymbol(name.toTypeName, origin, pos, (flags | EXISTENTIAL) & ~PARAM) + skolem setInfo (info cloneInfo skolem) } // don't test directly -- use isGADTSkolem @@ -577,6 +582,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isConstructor = false def isEarlyInitialized = false def isGetter = false + def isDefaultGetter = false def isLocalDummy = false def isMixinConstructor = false def isOverloaded = false @@ -2502,14 +2508,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => * If !settings.debug translates expansions of operators back to operator symbol. * E.g. $eq => =. * If settings.uniqid, adds id. + * If settings.Yshowsymowners, adds owner's id * If settings.Yshowsymkinds, adds abbreviated symbol kind. */ def nameString: String = { val name_s = if (settings.debug.value) "" + unexpandedName else unexpandedName.dropLocal.decode - val id_s = if (settings.uniqid.value) "#" + id else "" val kind_s = if (settings.Yshowsymkinds.value) "#" + abbreviatedKindString else "" - name_s + id_s + kind_s + name_s + idString + kind_s } def fullNameString: String = { @@ -2523,7 +2529,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => } /** If settings.uniqid is set, the symbol's id, else "" */ - final def idString = if (settings.uniqid.value) "#"+id else "" + final def idString = { + val id_s = if (settings.uniqid.value) "#"+id else "" + val owner_s = if (settings.Yshowsymowners.value) "@"+owner.id else "" + id_s + owner_s + } /** String representation, including symbol's kind e.g., "class Foo", "method Bar". * If hasMeaninglessName is true, uses the owner's name to disambiguate identity. @@ -2675,6 +2685,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def isSetterParameter = isValueParameter && owner.isSetter override def isAccessor = this hasFlag ACCESSOR override def isGetter = isAccessor && !isSetter + override def isDefaultGetter = name containsName nme.DEFAULT_GETTER_STRING override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged. override def isLocalDummy = nme.isLocalDummyName(name) override def isClassConstructor = name == nme.CONSTRUCTOR @@ -3459,6 +3470,21 @@ trait Symbols extends api.Symbols { self: SymbolTable => mapList(syms1)(_ substInfo (syms, syms1)) } + /** Derives a new list of symbols from the given list by mapping the given + * list of `syms` and `as` across the given function. + * Then fixes the info of all the new symbols + * by substituting the new symbols for the original symbols. + * + * @param syms the prototypical symbols + * @param as arguments to be passed to symFn together with symbols from syms (must be same length) + * @param symFn the function to create new symbols + * @return the new list of info-adjusted symbols + */ + def deriveSymbols2[A](syms: List[Symbol], as: List[A], symFn: (Symbol, A) => Symbol): List[Symbol] = { + val syms1 = map2(syms, as)(symFn) + mapList(syms1)(_ substInfo (syms, syms1)) + } + /** Derives a new Type by first deriving new symbols as in deriveSymbols, * then performing the same oldSyms => newSyms substitution on `tpe` as is * performed on the symbol infos in deriveSymbols. @@ -3472,6 +3498,22 @@ trait Symbols extends api.Symbols { self: SymbolTable => val syms1 = deriveSymbols(syms, symFn) tpe.substSym(syms, syms1) } + + /** Derives a new Type by first deriving new symbols as in deriveSymbols2, + * then performing the same oldSyms => newSyms substitution on `tpe` as is + * performed on the symbol infos in deriveSymbols. + * + * @param syms the prototypical symbols + * @param as arguments to be passed to symFn together with symbols from syms (must be same length) + * @param symFn the function to create new symbols based on `as` + * @param tpe the prototypical type + * @return the new symbol-subsituted type + */ + def deriveType2[A](syms: List[Symbol], as: List[A], symFn: (Symbol, A) => Symbol)(tpe: Type): Type = { + val syms1 = deriveSymbols2(syms, as, symFn) + tpe.substSym(syms, syms1) + } + /** Derives a new Type by instantiating the given list of symbols as * WildcardTypes. * diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 7ed808a7fb..6011289baf 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -691,11 +691,11 @@ abstract class TreeGen { } /** Create tree for pattern definition <val pat0 = rhs> */ - def mkPatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] = + def mkPatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] = mkPatDef(Modifiers(0), pat, rhs) /** Create tree for pattern definition <mods val pat0 = rhs> */ - def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] = matchVarPattern(pat) match { + def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] = matchVarPattern(pat) match { case Some((name, tpt)) => List(atPos(pat.pos union rhs.pos) { ValDef(mods, name.toTermName, tpt, rhs) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 8cad2497c1..0b42a8f9ac 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -281,6 +281,10 @@ abstract class TreeInfo { } } + def isDefaultGetter(tree: Tree) = { + tree.symbol != null && tree.symbol.isDefaultGetter + } + /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the * same object? */ @@ -864,13 +868,8 @@ abstract class TreeInfo { case _ => false }) - def isMacroApplication(tree: Tree): Boolean = !tree.isDef && { - val sym = tree.symbol - sym != null && sym.isTermMacro && !sym.isErroneous - } - - def isMacroApplicationOrBlock(tree: Tree): Boolean = tree match { - case Block(_, expr) => isMacroApplicationOrBlock(expr) - case tree => isMacroApplication(tree) + def isMacroApplication(tree: Tree): Boolean = tree match { + case Block(_, expr) => isMacroApplication(expr) + case tree => !tree.isDef && tree.symbol != null && tree.symbol.isTermMacro && !tree.symbol.isErroneous } } diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 5b4b7fd2a4..7a6862a770 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1683,6 +1683,15 @@ trait Trees extends api.Trees { def duplicateAndKeepPositions(tree: Tree) = new Duplicator(focusPositions = false) transform tree + // this is necessary to avoid crashes like https://github.com/scalamacros/paradise/issues/1 + // when someone tries to c.typecheck a naked MemberDef + def wrappingIntoTerm(tree: Tree)(op: Tree => Tree): Tree = { + op(build.SyntacticBlock(tree :: Nil)) match { + case build.SyntacticBlock(tree :: Nil) => tree + case tree => tree + } + } + // ------ copiers ------------------------------------------- def copyDefDef(tree: Tree)( diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 089684413d..3ede21d5e3 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -93,10 +93,11 @@ trait Types private final val traceTypeVars = sys.props contains "scalac.debug.tvar" private final val breakCycles = settings.breakCycles.value - /** In case anyone wants to turn off type parameter bounds being used + /** In case anyone wants to turn on type parameter bounds being used * to seed type constraints. */ private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints" + private final val sharperSkolems = sys.props contains "scalac.experimental.sharper-skolems" protected val enableTypeVarExperimentals = settings.Xexperimental.value @@ -2574,56 +2575,58 @@ trait Types override def baseTypeSeq = underlying.baseTypeSeq map maybeRewrap override def isHigherKinded = false + // TODO: check invariant that all quantifiers have the same (existing) owner + private def quantifierOwner = quantified collectFirst { case q if q.owner.exists => q.owner } getOrElse NoSymbol + + // Is this existential of the form: T[Q1, ..., QN] forSome { type Q1 >: L1 <: U1, ..., QN >: LN <: UN} + private def isStraightApplication = (quantified corresponds underlying.typeArgs){ (q, a) => q.tpe =:= a } + /** [SI-6169, SI-8197 -- companion to SI-1786] * - * Approximation to improve the bounds of a Java-defined existential type, - * based on the bounds of the type parameters of the quantified type - * In Scala syntax, given a java-defined class C[T <: String], the existential type C[_] - * is improved to C[_ <: String] before skolemization, which captures (get it?) what Java does: - * enter the type paramers' bounds into the context when checking subtyping/type equality of existential types + * Approximation to improve the bounds of a Java-defined existential type, + * based on the bounds of the type parameters of the quantified type + * In Scala syntax, given a java-defined class C[T <: String], the existential type C[_] + * is improved to C[_ <: String] before skolemization, which captures (get it?) what Java does: + * enter the type paramers' bounds into the context when checking subtyping/type equality of existential types * - * (Also tried doing this once during class file parsing or when creating the existential type, - * but that causes cyclic errors because it happens too early.) + * Also tried doing this once during class file parsing or when creating the existential type, + * but that causes cyclic errors because it happens too early. + * + * NOTE: we're only modifying the skolems to avoid leaking the sharper bounds to `quantified` (SI-8283) * * TODO: figure out how to do this earlier without running into cycles, so this can subsume the fix for SI-1786 */ - private def sharpenQuantifierBounds(): Unit = { - /* Check that we're looking at rawToExistential's handiwork - * (`existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))`). - * We can't do this sharpening there because we'll run into cycles. - */ - def rawToExistentialCreatedMe = (quantified corresponds underlying.typeArgs){ (q, a) => q.tpe =:= a } - - if (underlying.typeSymbol.isJavaDefined && rawToExistentialCreatedMe) { - val tpars = underlying.typeSymbol.initialize.typeParams // TODO: is initialize needed? - debuglog(s"sharpen bounds: $this | ${underlying.typeArgs.map(_.typeSymbol)} <-- ${tpars.map(_.info)}") - - foreach2(quantified, tpars) { (quant, tparam) => - // TODO: check `tparam.info.substSym(tpars, quantified) <:< quant.info` instead (for some weird reason not working for test/t6169/ExistF) - // for now, crude approximation for the common case - if (quant.info.bounds.isEmptyBounds && !tparam.info.bounds.isEmptyBounds) { - // avoid creating cycles [pos/t2940] that consist of an existential quantifier's - // bounded by an existential type that unhygienically has that quantifier as its own quantifier - // (TODO: clone latter existential with fresh quantifiers -- not covering this case for now) - if ((existentialsInType(tparam.info) intersect quantified).isEmpty) - quant setInfo tparam.info.substSym(tpars, quantified) - } - } - } + override def skolemizeExistential(owner0: Symbol, origin: AnyRef) = { + val owner = owner0 orElse quantifierOwner - _sharpenQuantifierBounds = false - } - private[this] var _sharpenQuantifierBounds = true - - override def skolemizeExistential(owner: Symbol, origin: AnyRef) = { // do this here because it's quite close to what Java does: // when checking subtyping/type equality, enter constraints // derived from the existentially quantified type into the typing environment // (aka \Gamma, which tracks types for variables and constraints/kinds for types) // as a nice bonus, delaying this until we need it avoids cyclic errors - if (_sharpenQuantifierBounds) sharpenQuantifierBounds + def tpars = underlying.typeSymbol.initialize.typeParams + + def newSkolem(quant: Symbol) = owner.newExistentialSkolem(quant, origin) + def newSharpenedSkolem(quant: Symbol, tparam: Symbol): Symbol = { + def emptyBounds(sym: Symbol) = sym.info.bounds.isEmptyBounds + + // avoid creating cycles [pos/t2940] that consist of an existential quantifier's + // bounded by an existential type that unhygienically has that quantifier as its own quantifier + // (TODO: clone latter existential with fresh quantifiers -- not covering this case for now) + val canSharpen = ( + emptyBounds(quant) && !emptyBounds(tparam) + && (existentialsInType(tparam.info) intersect quantified).isEmpty + ) + + val skolemInfo = if (!canSharpen) quant.info else tparam.info.substSym(tpars, quantified) + + owner.newExistentialSkolem(quant.name.toTypeName, skolemInfo, quant.flags, quant.pos, origin) + } + + val canSharpenBounds = (underlying.typeSymbol.isJavaDefined || sharperSkolems) && isStraightApplication - deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying) + if (canSharpenBounds) deriveType2(quantified, tpars, newSharpenedSkolem)(underlying) + else deriveType(quantified, newSkolem)(underlying) } private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map { diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index 816916787e..048fe9ef37 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -39,6 +39,7 @@ abstract class MutableSettings extends AbsSettings { def Xprintpos: BooleanSetting def Yposdebug: BooleanSetting def Yrangepos: BooleanSetting + def Yshowsymowners: BooleanSetting def Yshowsymkinds: BooleanSetting def breakCycles: BooleanSetting def debug: BooleanSetting diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index de5ba99900..d46846fc21 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -36,6 +36,7 @@ private[reflect] class Settings extends MutableSettings { val Xprintpos = new BooleanSetting(false) val Yposdebug = new BooleanSetting(false) val Yrangepos = new BooleanSetting(false) + val Yshowsymowners = new BooleanSetting(false) val Yshowsymkinds = new BooleanSetting(false) val breakCycles = new BooleanSetting(false) val debug = new BooleanSetting(false) |