Skip to content

Commit

Permalink
(1) Removed generation of $tag method for inter...
Browse files Browse the repository at this point in the history
(1) Removed generation of $tag method for interfaces (2) improved type
inference for clsoures (3) redesign of CharSequence and regex.
  • Loading branch information
odersky committed Apr 7, 2008
1 parent 67af71b commit 34fe33a
Show file tree
Hide file tree
Showing 19 changed files with 492 additions and 70 deletions.
12 changes: 8 additions & 4 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2200,9 +2200,7 @@ trait Parsers extends NewScanners with MarkupParsers {
template, template.parents, makeSelfDef(nme.WILDCARD, thistpe), template.body)
} else syntaxError("`requires' cannot be combined with explicit self type", false)
}
val mods1 = if (mods.hasFlag(Flags.TRAIT) &&
(template.body forall treeInfo.isInterfaceMember))
mods | Flags.INTERFACE
val mods1 = if (isInterface(mods, template.body)) mods | Flags.INTERFACE
else mods
val result = ClassDef(mods1, name, tparams, template)
implicitClassViews = savedViews
Expand Down Expand Up @@ -2271,6 +2269,9 @@ trait Parsers extends NewScanners with MarkupParsers {
}
}

def isInterface(mods: Modifiers, body: List[Tree]) =
(mods.hasFlag(Flags.TRAIT) && (body forall treeInfo.isInterfaceMember))

/** ClassTemplateOpt ::= extends ClassTemplate | [[extends] TemplateBody]
* TraitTemplateOpt ::= extends TraitTemplate | [[extends] TemplateBody]
*/
Expand All @@ -2286,7 +2287,10 @@ trait Parsers extends NewScanners with MarkupParsers {
(List(), List(List()), self, body)
}
var parents = parents0
if (name != nme.ScalaObject.toTypeName) parents = parents ::: List(scalaScalaObjectConstr)
if (name != nme.ScalaObject.toTypeName && !isInterface(mods, body))
parents = parents ::: List(scalaScalaObjectConstr)
if (parents.isEmpty)
parents = List(scalaAnyRefConstr)
if (mods.hasFlag(Flags.CASE)) parents = parents ::: List(productConstr)
val tree = Template(parents, self, constrMods, vparamss, argss, body)
// @S: if nothing parsed, don't use next position!
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ trait Contexts { self: Analyzer =>
var checking = false
var retyping = false

var savedTypeBounds: List[(Symbol, Type)] = List()
var savedTypeBounds: List[(Symbol, Type)] = List() // saved type bounds
// for type parameters which are narrowed in a GADT

def intern0 : Context = {
if (this eq NoContext) return this
Expand Down
13 changes: 13 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ trait EtaExpansion { self: Analyzer =>
import global._
import posAssigner.atPos

object etaExpansion {
def unapply(tree: Tree): Option[(List[ValDef], Tree, List[Tree])] = tree match {
case Function(vparams, Apply(fn, args))
if (List.forall2(vparams, args) {
case (vparam, Ident(name)) => vparam.name == name
case _ => false
}) =>
Some((vparams, fn, args))
case _ =>
None
}
}

/** <p>
* Expand partial function applications of type <code>type</code>.
* </p><pre>
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/Infer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,7 @@ trait Infer {
val ptvars = ptparams map freshVar
val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
if (!isPopulated(tp, pt1)) {
error(pos, "pattern type is incompatibe with expected type"+foundReqMsg(pattp, pt))
error(pos, "pattern type is incompatible with expected type"+foundReqMsg(pattp, pt))
return pattp
}
ptvars foreach instantiateTypeVar
Expand All @@ -1169,7 +1169,7 @@ trait Infer {
if (pat.tpe <:< pt1)
ptvars foreach instantiateTypeVar
else
error(pat.pos, "pattern type is incompatibe with expected type"+foundReqMsg(pat.tpe, pt))
error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt))
}

object toOrigin extends TypeMap {
Expand Down
66 changes: 60 additions & 6 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1449,17 +1449,30 @@ trait Typers { self: Analyzer =>
errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
else {
val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
if (vparam.tpt.isEmpty)
if (vparam.tpt.isEmpty) {
vparam.tpt.tpe =
if (isFullyDefined(argpt)) argpt
else {
fun match {
case etaExpansion(vparams, fn, args) if !codeExpected =>
println("typing eta "+fn)
silent(_.typed(fn, funMode(mode), pt)) match {
case fn1: Tree =>
val ftpe = normalize(fn1.tpe) baseType FunctionClass(fun.vparams.length)
if (isFunctionType(ftpe) && isFullyDefined(ftpe))
return typedFunction(fun, mode, ftpe)
case _ =>
}
case _ =>
}
error(
vparam.pos,
"missing parameter type"+
(if (vparam.mods.hasFlag(SYNTHETIC)) " for expanded function "+fun
else ""))
ErrorType
}
}
enterSym(context, vparam)
if (context.retyping) context.scope enter vparam.symbol
vparam.symbol
Expand Down Expand Up @@ -1593,6 +1606,31 @@ trait Typers { self: Analyzer =>
}
}

/** Does function need to be instantiated, because a missing parameter
* in an argument closure overlaps with an uninstantiated formal?
*/
def needsInstantiation(tparams: List[Symbol], formals: List[Type], args: List[Tree]) = {
def isLowerBounded(tparam: Symbol) = {
val losym = tparam.info.bounds.lo.typeSymbol
losym != AllClass && losym != AllRefClass
}
List.exists2(formals, args) {
case (formal, Function(vparams, _)) =>
(vparams exists (_.tpt.isEmpty)) &&
vparams.length <= MaxFunctionArity &&
(formal baseType FunctionClass(vparams.length) match {
case TypeRef(_, _, formalargs) =>
List.exists2(formalargs, vparams) ((formalarg, vparam) =>
vparam.tpt.isEmpty && (tparams exists (formalarg contains))) &&
(tparams forall isLowerBounded)
case _ =>
false
})
case _ =>
false
}
}

/**
* @param tree ...
* @param fun0 ...
Expand All @@ -1604,12 +1642,19 @@ trait Typers { self: Analyzer =>
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
var fun = fun0
if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) {
// preadapt symbol to number of arguments given
val argtypes = args map (arg => AllClass.tpe)
// preadapt symbol to number and shape of arguments given
def shapeType(arg: Tree): Type = arg match {
case Function(vparams, body) =>
functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
case _ =>
AllClass.tpe
}
val argtypes = args map shapeType
val pre = fun.symbol.tpe.prefix
var sym = fun.symbol filter { alt =>
isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
}
//println("narrowed to "+sym+":"+sym.info+"/"+argtypes)
if (sym hasFlag OVERLOADED) {
// eliminate functions that would result from tupling transforms
val sym1 = sym filter (alt => hasExactlyNumParams(followApply(alt.tpe), argtypes.length))
Expand Down Expand Up @@ -1673,6 +1718,10 @@ trait Typers { self: Analyzer =>
atPos(tree.pos) { gen.mkNil setType restpe }
} else
constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe)))
} else if (needsInstantiation(tparams, formals, args1)) {
//println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info)))
inferExprInstance(fun, tparams, WildcardType)
doTypedApply(tree, fun, args1, mode, pt)
} else {
assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
Expand Down Expand Up @@ -3527,9 +3576,14 @@ trait Typers { self: Analyzer =>
List()
}

def implicitManifest(pt: Type): Tree = pt match {
case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
case _ => EmptyTree
def implicitManifest(pt: Type): Tree = {
// test below is designed so that ManifestClass need not be loaded
// (because it's not available everywhere)
if (pt.typeSymbol.fullNameString == "scala.reflect.Manifest")
pt match {
case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
}
else EmptyTree
}

var tree = searchImplicit(context.implicitss, true)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ trait Unapplies { self: Analyzer =>
*/
def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) {
var parents = List(gen.scalaScalaObjectConstr)
if (cdef.tparams.isEmpty && constrParams(cdef).length == 1)
if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParams(cdef).length == 1)
parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt),
Ident(cdef.name)) :: parents
ModuleDef(
Expand Down
8 changes: 7 additions & 1 deletion src/library/scala/Predef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@ object Predef {
implicit def forceRandomAccessCharSeq(x: runtime.RichString): String = x.mkString
implicit def lazyStreamToConsable[A](xs: => Stream[A]) = new runtime.StreamCons(xs)

def currentThread = java.lang.Thread.currentThread()
implicit def seqToCharSequence(xs: RandomAccessSeq[Char]): CharSequence = new CharSequence {
def length: Int = xs.length
def charAt(index: Int): Char = xs(index)
def subSequence(start: Int, end: Int): CharSequence = seqToCharSequence(xs.slice(start, end))
override def toString: String = xs.mkString("")
}

def currentThread = java.lang.Thread.currentThread()
}
12 changes: 10 additions & 2 deletions src/library/scala/Seq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ trait Seq[+A] extends AnyRef with PartialFunction[Int, A] with Collection[A] {
result.toList
}

/** A sub-sequence of <code>len</code> elements
* starting at index <code>from</code> (non-strict)
/** A sub-sequence starting at index <code>from</code>
* and ending (non-inclusive) at index <code>until</code> (non-strict)
*
* @param from The index of the first element of the slice
* @param until The index of the element following the slice
Expand All @@ -323,6 +323,14 @@ trait Seq[+A] extends AnyRef with PartialFunction[Int, A] with Collection[A] {
*/
def slice(from: Int, until: Int): Seq[A] = drop(from).take(until - from)

/** A sub-sequence starting at index <code>from</code>
* and extending up to the length of the current sequence (non-strict)
*
* @param from The index of the first element of the slice
* @throws IndexOutOfBoundsException if <code>from &lt; 0</code>
*/
def slice(from: Int): Seq[A] = slice(from, length)

/** Returns the longest prefix of this sequence whose elements satisfy
* the predicate <code>p</code>.
*
Expand Down
7 changes: 7 additions & 0 deletions src/library/scala/StringBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -943,4 +943,11 @@ object StringBuilder {
}
-1
}

implicit def toCharSequence(sb: StringBuilder): java.lang.CharSequence = new java.lang.CharSequence {
def length: Int = sb.length
def charAt(index: Int): Char = sb.charAt(index)
def subSequence(start: Int, end: Int): java.lang.CharSequence = sb.substring(start, end)
override def toString: String = sb.toString
}
}

0 comments on commit 34fe33a

Please sign in to comment.