From 16d3cf1f8f22c04559145b35bb5f6c0aacfb0d8c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 23 Jul 2007 18:22:29 +0000 Subject: many bug fixes; short syntax for structural types. --- .../scala/tools/nsc/ast/parser/Parsers.scala | 10 +- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 4 +- src/compiler/scala/tools/nsc/symtab/Symbols.scala | 3 +- src/compiler/scala/tools/nsc/symtab/Types.scala | 19 ++- .../scala/tools/nsc/transform/Erasure.scala | 2 +- .../scala/tools/nsc/transform/ExplicitOuter.scala | 4 +- .../scala/tools/nsc/transform/UnCurry.scala | 63 ++++++---- .../scala/tools/nsc/typechecker/Infer.scala | 89 +++++++------ .../scala/tools/nsc/typechecker/RefChecks.scala | 18 +++ .../tools/nsc/typechecker/SyntheticMethods.scala | 91 +++++++------- .../scala/tools/nsc/typechecker/Typers.scala | 138 ++++++++++++++------- .../scala/collection/immutable/TreeSet.scala | 6 - test/files/neg/bug835.check | 9 +- test/files/neg/bug875.check | 12 +- test/files/pos/bug602.scala | 4 + test/files/run/existentials.scala | 3 + test/files/run/regularpatmatnew.scala | 2 +- test/files/run/withIndex.check | 2 + test/files/run/withIndex.scala | 7 +- 19 files changed, 307 insertions(+), 179 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index c0cefd5347..68a34def62 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -722,7 +722,10 @@ trait Parsers { /** InfixType ::= CompoundType {id [nl] CompoundType} */ def infixType(isPattern: Boolean, mode: Int): Tree = - infixTypeRest(inCurrentPos, annotType(isPattern), isPattern, mode) + infixTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern, mode) + + def infixTypeFirst(isPattern: boolean) = + if (inToken == LBRACE) scalaAnyRefConstr else annotType(isPattern) def infixTypeRest(pos: ScanPosition, t0: Tree, isPattern: Boolean, mode: Int): Tree = { val t = compoundTypeRest(pos, t0, isPattern) @@ -742,9 +745,10 @@ trait Parsers { } /** CompoundType ::= AnnotType {with AnnotType} [Refinement] + * | Refinement */ def compoundType(isPattern: Boolean): Tree = - compoundTypeRest(inCurrentPos, annotType(isPattern), isPattern) + compoundTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern) def compoundTypeRest(pos: ScanPosition, t: Tree, isPattern: Boolean): Tree = { var ts = new ListBuffer[Tree] + t @@ -1129,7 +1133,7 @@ trait Parsers { } } - /* SimpleExpr ::= new ClassTemplate + /* SimpleExpr ::= new (ClassTemplate | TemplateBody) * | BlockExpr * | SimpleExpr1 [`_'] * SimpleExpr1 ::= literal diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index fcee9c4d0e..2848469215 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -140,7 +140,9 @@ abstract class TreeBuilder { /** Create tree representing an object creation */ def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree], argss: List[List[Tree]]): Tree = - if (parents.tail.isEmpty && stats.isEmpty) + if (parents.isEmpty) + makeNew(List(scalaAnyRefConstr), self, stats, argss) + else if (parents.tail.isEmpty && stats.isEmpty) New(parents.head, argss) else { val x = nme.ANON_CLASS_NAME.toTypeName diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index dd2ac94f49..947e3c1151 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -215,6 +215,7 @@ trait Symbols { final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) final def isAnonymousClass = isClass && (originalName startsWith nme.ANON_CLASS_NAME) // startsWith necessary because name may grow when lifted and also because of anonymous function classes + def isAnonymousFunction = hasFlag(SYNTHETIC) && (originalName startsWith nme.ANON_FUN_NAME) final def isRefinementClass = isClass && name == nme.REFINE_CLASS_NAME.toTypeName; // no lifting for refinement classes final def isModuleClass = isClass && hasFlag(MODULE) final def isPackageClass = isClass && hasFlag(PACKAGE) @@ -585,7 +586,7 @@ trait Symbols { def typeConstructor: Type = throw new Error("typeConstructor inapplicable for " + this) - def tpeHK = if(isType) typeConstructor else tpe // @M! used in memberType + def tpeHK = if (isType) typeConstructor else tpe // @M! used in memberType /** The type parameters of this symbol */ def unsafeTypeParams: List[Symbol] = diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index b78cbb5583..57c8e4e60b 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1957,7 +1957,7 @@ A type's typeSymbol should never be inspected directly. override def toString = lobounds.mkString("[ _>:(", ",", ") ") + - hibounds.mkString("| _<:(", ",", ") | _= ") + inst + hibounds.mkString("| _<:(", ",", ") ] _= ") + inst } /** A prototype for mapping a function over all possible types @@ -2166,15 +2166,15 @@ A type's typeSymbol should never be inspected directly. def toInstance(pre: Type, clazz: Symbol): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) mapOver(tp) //@M! see test pos/tcpoly_return_overriding.scala why mapOver is necessary else { - val symclazz = sym.owner; def throwError = - throw new Error("" + tp + " in " + symclazz + + throw new Error("" + tp + sym.locationString + " cannot be instantiated from " + pre.widen); def instParam(ps: List[Symbol], as: List[Type]): Type = if (ps.isEmpty) throwError else if (sym eq ps.head) // @M! don't just replace the whole thing, might be followed by type application appliedType(as.head, List.mapConserve(args)(this)) // @M: was as.head else instParam(ps.tail, as.tail); + val symclazz = sym.owner if (symclazz == clazz && (pre.widen.typeSymbol isNonBottomSubClass symclazz)) pre.baseType(symclazz) match { case TypeRef(_, basesym, baseargs) => @@ -2609,6 +2609,17 @@ A type's typeSymbol should never be inspected directly. * @return true, iff `tp1' and `tp2' denote * equivalent types. */ + var si = 0 + def isSameType0(tp1: Type, tp2: Type): Boolean = { + for (i <- 0 until si) print(" "); + println(tp1+" =:= "+tp2) + si += 1 + if (si > 10) throw new Error() + val res = isSameType0(tp1, tp2) + si -= 1 + res + } + def isSameType(tp1: Type, tp2: Type): Boolean = { (tp1, tp2) match { case (ErrorType, _) => true @@ -2777,7 +2788,7 @@ A type's typeSymbol should never be inspected directly. (phase.erasedTypes || pre1 <:< pre2) && (sym2 == AnyClass || isSubArgs(args1, args2, sym1.typeParams)) //@M: Any is kind-polymorphic || - sym1.isAbstractType && !(tp1 =:= tp1.bounds.hi) && (tp1.bounds.hi <:< tp2) + sym1.isAbstractType && !(tp1 =:= tp1.bounds.hi) && (tp1.bounds.hi <:< tp2) || sym2.isAbstractType && !(tp2 =:= tp2.bounds.lo) && (tp1 <:< tp2.bounds.lo) || diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 09cfa4a627..ce5a62aff1 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -793,7 +793,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { List(TypeTree(tp) setPos targ.pos)) setPos fn.pos, List()) setPos tree.pos targ.tpe match { - case SingleType(pre, sym) => + case SingleType(_, _) | ThisType(_) | SuperType(_, _) => val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq atPos(tree.pos) { Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe))) diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index d0e2bf1eca..736a5539b5 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -412,14 +412,14 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter val ncases = transformCaseDefs(cases) var checkExhaustive = true - def isUnsealedAnnotation(tpe: Type) = tpe match { + def isUncheckedAnnotation(tpe: Type) = tpe match { case AnnotatedType(List(AnnotationInfo(atp, _, _)), _) if atp.typeSymbol == UncheckedClass => true case _ => false } nselector match { - case Typed(nselector1, tpt) if isUnsealedAnnotation(tpt.tpe) => + case Typed(nselector1, tpt) if isUncheckedAnnotation(tpt.tpe) => nselector = nselector1 checkExhaustive = false case _ => diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 812896337f..7c3bd8d65e 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -235,8 +235,9 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { * to: * * class $anon() extends Object() with PartialFunction[T, R] with ScalaObject { - * def apply(x: T): R = body; - * def isDefinedAt(x: T): boolean = x match { + * def apply(x: T): R = (x: @unchecked) match { + * { case P_i if G_i => E_i }_i=1..n + * def isDefinedAt(x: T): boolean = (x: @unchecked) match { * case P_1 if G_1 => true * ... * case P_n if G_n => true @@ -264,29 +265,43 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { anonClass.info.decls enter applyMethod; for (vparam <- fun.vparams) vparam.symbol.owner = applyMethod; new ChangeOwnerTraverser(fun.symbol, applyMethod).traverse(fun.body); - var members = List( - DefDef(Modifiers(FINAL), nme.apply, List(), List(fun.vparams), TypeTree(restpe), fun.body) - setSymbol applyMethod); - if (fun.tpe.typeSymbol == PartialFunctionClass) { - val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt) - .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe)) - anonClass.info.decls enter isDefinedAtMethod - def idbody(idparam: Symbol) = fun.body match { - case Match(_, cases) => - val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam)); - def transformCase(cdef: CaseDef): CaseDef = - substParam( - resetAttrs( - CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(true)))) - if (cases exists treeInfo.isDefaultCase) Literal(true) - else - Match( - Ident(idparam), - (cases map transformCase) ::: - List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false)))) - } - members = DefDef(isDefinedAtMethod, vparamss => idbody(vparamss.head.head)) :: members; + def applyMethodDef(body: Tree) = + DefDef(Modifiers(FINAL), nme.apply, List(), List(fun.vparams), TypeTree(restpe), body) + .setSymbol(applyMethod) + def mkUnchecked(tree: Tree) = tree match { + case Match(selector, cases) => + atPos(tree.pos) { + Match( + Annotated(Annotation(New(TypeTree(UncheckedClass.tpe), List(List())), List()), selector), + cases) + } + case _ => + tree } + val members = + if (fun.tpe.typeSymbol == PartialFunctionClass) { + val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt) + .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe)) + anonClass.info.decls enter isDefinedAtMethod + def idbody(idparam: Symbol) = fun.body match { + case Match(_, cases) => + val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam)); + def transformCase(cdef: CaseDef): CaseDef = + substParam( + resetAttrs( + CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(true)))) + if (cases exists treeInfo.isDefaultCase) Literal(true) + else + Match( + Ident(idparam), + (cases map transformCase) ::: + List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false)))) + } + List(applyMethodDef(mkUnchecked(fun.body)), + DefDef(isDefinedAtMethod, vparamss => mkUnchecked(idbody(vparamss.head.head)))) + } else { + List(applyMethodDef(fun.body)) + } localTyper.typed { atPos(fun.pos) { Block( diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index ad8fb895c4..a18e2b80eb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -574,6 +574,11 @@ trait Infer { */ def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = { def isNullary(tpe: Type) = tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty + def isMethod(tpe: Type) = tpe match { + case MethodType(_, _) | PolyType(_, _) => true + case _ => false + } + isMethod(tpe2) && !isMethod(tpe1) || isNullary(tpe1) && !isNullary(tpe2) || isStrictlyBetter(tpe1, tpe2) } @@ -850,7 +855,8 @@ trait Infer { def computeArgs = try { val targs = solvedTypes(tvars, undetparams, undetparams map varianceInType(restpe), true) - checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") +// checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") +// no checkBounds here. If we enable it, test bug602 fails. new TreeTypeSubstituter(undetparams, targs).traverse(tree) } catch { case ex: NoInstance => @@ -914,44 +920,51 @@ trait Infer { } } - def checkCheckable(pos: Position, tp: Type) { - def patternWarning(tp: Type, prefix: String) = - context.unit.uncheckedWarning(pos, prefix+tp+" in type pattern is unchecked since it is eliminated by erasure") - def isLocalBinding(sym: Symbol) = - sym.isAbstractType && - (sym.name == nme.WILDCARD.toTypeName || { - val e = context.scope.lookupEntry(sym.name) - (e ne null) && e.sym == sym && e.owner == context.scope - }) - tp match { - case SingleType(pre, _) => - checkCheckable(pos, pre) - case TypeRef(pre, sym, args) => - if (sym.isAbstractType) - patternWarning(tp, "abstract type ") - else if (sym == AllClass || sym == AllRefClass) - error(pos, "this type cannot be used in a type pattern") - else - for (arg <- args) { - if (sym == ArrayClass) checkCheckable(pos, arg) - else arg match { - case TypeRef(_, sym, _) if isLocalBinding(sym) => - ; - case _ => - patternWarning(arg, "non variable type-argument ") + def checkCheckable(pos: Position, tp: Type, kind: String) { + def patternWarning(tp: Type, prefix: String) = { + context.unit.uncheckedWarning(pos, prefix+tp+" in type"+kind+" is unchecked since it is eliminated by erasure") + } + def check(tp: Type, bound: List[Symbol]) { + def isLocalBinding(sym: Symbol) = + sym.isAbstractType && + ((bound contains sym) || + sym.name == nme.WILDCARD.toTypeName || { + val e = context.scope.lookupEntry(sym.name) + (e ne null) && e.sym == sym && e.owner == context.scope + }) + tp match { + case SingleType(pre, _) => + check(pre, bound) + case TypeRef(pre, sym, args) => + if (sym.isAbstractType) + patternWarning(tp, "abstract type ") + else if (sym == AllClass || sym == AllRefClass) + error(pos, "this type cannot be used in a type pattern") + else + for (arg <- args) { + if (sym == ArrayClass) check(arg, bound) + else arg match { + case TypeRef(_, sym, _) if isLocalBinding(sym) => + ; + case _ => + patternWarning(arg, "non variable type-argument ") + } } - } - checkCheckable(pos, pre) - case RefinedType(parents, decls) => - if (decls.isEmpty) for (p <- parents) checkCheckable(pos, p) - else patternWarning(tp, "refinement ") - case ThisType(_) => - ; - case NoPrefix => - ; - case _ => - patternWarning(tp, "type ") + check(pre, bound) + case RefinedType(parents, decls) => + if (decls.isEmpty) for (p <- parents) check(p, bound) + else patternWarning(tp, "refinement ") + case ExistentialType(quantified, tp1) => + check(tp1, bound ::: quantified) + case ThisType(_) => + ; + case NoPrefix => + ; + case _ => + patternWarning(tp, "type ") + } } + check(tp, List()) } /** Type intersection of simple type tp1 with general @@ -972,7 +985,7 @@ trait Infer { } def inferTypedPattern(pos: Position, pattp: Type, pt: Type): Type = { - checkCheckable(pos, pattp) + checkCheckable(pos, pattp, " pattern") if (!(pattp <:< pt)) { val tpparams = freeTypeParamsOfTerms.collect(pattp) if (settings.debug.value) log("free type params (1) = " + tpparams) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 13f19feb24..9fd430187e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -61,6 +61,7 @@ abstract class RefChecks extends InfoTransform { class RefCheckTransformer(unit: CompilationUnit) extends Transformer { var localTyper: analyzer.Typer = typer; + var currentApplication: Tree = EmptyTree // Override checking ------------------------------------------------------------ @@ -729,7 +730,17 @@ abstract class RefChecks extends InfoTransform { } } + def isRepeatedParamArg(tree: Tree) = currentApplication match { + case Apply(fn, args) => + !args.isEmpty && (args.last eq tree) && + fn.tpe.paramTypes.length == args.length && + fn.tpe.paramTypes.last.typeSymbol == RepeatedParamClass + case _ => + false + } + val savedLocalTyper = localTyper + val savedCurrentApplication = currentApplication val sym = tree.symbol var result = tree tree match { @@ -775,6 +786,7 @@ abstract class RefChecks extends InfoTransform { case Apply(fn, args) => checkSensible(tree.pos, fn, args) + currentApplication = tree case If(cond, thenpart, elsepart) => cond.tpe match { @@ -787,6 +799,11 @@ abstract class RefChecks extends InfoTransform { case New(tpt) => enterReference(tree.pos, tpt.tpe.typeSymbol) + case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) => + if (!isRepeatedParamArg(tree)) + unit.error(tree.pos, "no `: _*' annotation allowed here\n"+ + "(such annotations are only allowed in arguments to *-parameters)") + case Ident(name) => if (sym.isSourceMethod && sym.hasFlag(CASE)) result = toConstructor(tree.pos, tree.tpe) @@ -825,6 +842,7 @@ abstract class RefChecks extends InfoTransform { case _ => } localTyper = savedLocalTyper + currentApplication = savedCurrentApplication result } catch { case ex: TypeError => diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 2c08481680..69cc39cdc9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -37,9 +37,10 @@ trait SyntheticMethods { self: Analyzer => * @param unit ... * @return ... */ - def addSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = { + def addSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = try { - val localTyper = newTyper(context) + val localContext = if (reporter.hasErrors) context.makeSilent(false) else context + val localTyper = newTyper(localContext) def hasImplementation(name: Name): Boolean = { val sym = clazz.info.nonPrivateMember(name) @@ -124,14 +125,14 @@ trait SyntheticMethods { self: Analyzer => def equalsMethod: Tree = { val method = syntheticMethod( nme.equals_, 0, MethodType(List(AnyClass.tpe), BooleanClass.tpe)) - localTyper.typed { + val methodDef = DefDef( method, { vparamss => val that = Ident(vparamss.head.head) val constrParamTypes = clazz.primaryConstructor.tpe.paramTypes val hasVarArgs = !constrParamTypes.isEmpty && constrParamTypes.last.typeSymbol == RepeatedParamClass - if (clazz.isStatic) { + if (false && clazz.isStatic) { val target = getMember(ScalaRunTimeModule, if (hasVarArgs) nme._equalsWithVarArgs else nme._equals) Apply( Select( @@ -172,7 +173,7 @@ trait SyntheticMethods { self: Analyzer => } } ) - } + localTyper.typed(methodDef) } def isSerializable(clazz: Symbol): Boolean = @@ -243,51 +244,55 @@ trait SyntheticMethods { self: Analyzer => !sym.hasFlag(PRIVATE | PROTECTED) && sym.privateWithin == NoSymbol if (!phase.erasedTypes) { + try { + if (clazz hasFlag CASE) { + // case classes are implicitly declared serializable + clazz.attributes = AnnotationInfo(SerializableAttr.tpe, List(), List()) :: clazz.attributes - if (clazz hasFlag CASE) { - // case classes are implicitly declared serializable - clazz.attributes = AnnotationInfo(SerializableAttr.tpe, List(), List()) :: clazz.attributes + for (stat <- templ.body) { + if (stat.isDef && stat.symbol.isMethod && stat.symbol.hasFlag(CASEACCESSOR) && !isPublic(stat.symbol)) { + ts += newAccessorMethod(stat) + stat.symbol.resetFlag(CASEACCESSOR) + } + } - for (stat <- templ.body) { - if (stat.isDef && stat.symbol.isMethod && stat.symbol.hasFlag(CASEACCESSOR) && !isPublic(stat.symbol)) { - ts += newAccessorMethod(stat) - stat.symbol.resetFlag(CASEACCESSOR) + if (clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod + if (clazz.isModuleClass) { + if (!hasOverridingImplementation(Object_toString)) ts += moduleToStringMethod + } else { + if (!hasOverridingImplementation(Object_hashCode)) ts += forwardingMethod(nme.hashCode_) + if (!hasOverridingImplementation(Object_toString)) ts += forwardingMethod(nme.toString_) + if (!hasOverridingImplementation(Object_equals)) ts += equalsMethod } - } - if (clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod - if (clazz.isModuleClass) { - if (!hasOverridingImplementation(Object_toString)) ts += moduleToStringMethod - } else { - if (!hasOverridingImplementation(Object_hashCode)) ts += forwardingMethod(nme.hashCode_) - if (!hasOverridingImplementation(Object_toString)) ts += forwardingMethod(nme.toString_) - if (!hasOverridingImplementation(Object_equals)) ts += equalsMethod + if (!hasOverridingImplementation(Product_productPrefix)) ts += productPrefixMethod + val accessors = clazz.caseFieldAccessors + if (!hasOverridingImplementation(Product_productArity)) + ts += productArityMethod(accessors.length) + if (!hasOverridingImplementation(Product_productElement)) + ts += productElementMethod(accessors) } - if (!hasOverridingImplementation(Product_productPrefix)) ts += productPrefixMethod - val accessors = clazz.caseFieldAccessors - if (!hasOverridingImplementation(Product_productArity)) - ts += productArityMethod(accessors.length) - if (!hasOverridingImplementation(Product_productElement)) - ts += productElementMethod(accessors) - } - - if (clazz.isModuleClass && isSerializable(clazz)) { - // If you serialize a singleton and then deserialize it twice, - // you will have two instances of your singleton, unless you implement - // the readResolve() method (see http://www.javaworld.com/javaworld/ - // jw-04-2003/jw-0425-designpatterns_p.html) - if (!hasImplementation(nme.readResolve)) ts += readResolveMethod + if (clazz.isModuleClass && isSerializable(clazz)) { + // If you serialize a singleton and then deserialize it twice, + // you will have two instances of your singleton, unless you implement + // the readResolve() method (see http://www.javaworld.com/javaworld/ + // jw-04-2003/jw-0425-designpatterns_p.html) + if (!hasImplementation(nme.readResolve)) ts += readResolveMethod + } + if (!forCLDC && !forMSIL) + for (sym <- clazz.info.decls.toList) + if (!sym.getAttributes(BeanPropertyAttr).isEmpty) + if (sym.isGetter) + addBeanGetterMethod(sym) + else if (sym.isSetter) + addBeanSetterMethod(sym) + else if (sym.isMethod || sym.isType) + context.unit.error(sym.pos, "attribute `BeanProperty' is not applicable to " + sym) + } catch { + case ex: TypeError => + if (!reporter.hasErrors) throw ex } - if (!forCLDC && !forMSIL) - for (sym <- clazz.info.decls.toList) - if (!sym.getAttributes(BeanPropertyAttr).isEmpty) - if (sym.isGetter) - addBeanGetterMethod(sym) - else if (sym.isSetter) - addBeanSetterMethod(sym) - else if (sym.isMethod || sym.isType) - context.unit.error(sym.pos, "attribute `BeanProperty' is not applicable to " + sym) } val synthetics = ts.toList copy.Template( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cc77cab65a..0fee0c07dc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -253,6 +253,12 @@ trait Typers { self: Analyzer => ) case SingleType(pre, sym) => checkNotLocked(sym) +/* + case TypeBounds(lo, hi) => + var ok = true + for (t <- lo) ok = ok & checkNonCyclic(pos, t) + ok +*/ case st: SubType => checkNonCyclic(pos, st.supertype) case ct: CompoundType => @@ -296,12 +302,10 @@ trait Typers { self: Analyzer => } } - def checkRegPatOK(pos: Position, mode: Int) { - if ((mode & REGPATmode) == 0) { + def checkRegPatOK(pos: Position, mode: Int) = + if ((mode & REGPATmode) == 0) error(pos, "no regular expression pattern allowed here\n"+ "(regular expression patterns are only allowed in arguments to *-parameters)") - } - } /** Check that type of given tree does not contain local or private * components. @@ -342,7 +346,7 @@ trait Typers { self: Analyzer => else if (hiddenSymbols exists (_.isErroneous)) setError(tree) else if (isFullyDefined(pt)) tree setType pt //todo: eliminate else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate - check(owner, scope, pt, tree setType anonymousClassRefinement(tp1.typeSymbol)) + check(owner, scope, pt, tree setType classBound(tp1.typeSymbol)) else if (owner == NoSymbol) tree setType packSymbols(hiddenSymbols.reverse, tp1) else { // privates @@ -1249,11 +1253,7 @@ trait Typers { self: Analyzer => copy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType restpe } - /** - * @param clazz ... - * @return ... - */ - def anonymousClassRefinement(clazz: Symbol): Type = { + def classBound(clazz: Symbol): Type = { val tp = refinedType(clazz.info.parents, clazz.owner) val thistp = tp.typeSymbol.thisType for (sym <- clazz.info.decls.toList) { @@ -1460,17 +1460,7 @@ trait Typers { self: Analyzer => List.mapConserve(args)(arg => typedArg(arg, mode, 0, WildcardType)) def typedArgs(args: List[Tree], mode: Int, originalFormals: List[Type], adaptedFormals: List[Type]) = { - val varargs = isVarArgs(originalFormals) - if (!args.isEmpty) - args.last match { - case Typed(expr, Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) => - if (!varargs) - error(args.last.pos, "_*-argument does not correspond to *-parameter") - else if (originalFormals.length != adaptedFormals.length) - error(args.last.pos, "_*-argument may not appear after other arguments matching a *-parameter") - case _ => - } - if (varargs && (mode & PATTERNmode) != 0) { + if (isVarArgs(originalFormals)) { val nonVarCount = originalFormals.length - 1 val prefix = List.map2(args take nonVarCount, adaptedFormals take nonVarCount) ((arg, formal) => @@ -1528,7 +1518,8 @@ trait Typers { self: Analyzer => case ex => errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) } } else if (formals.length != args1.length) { - errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) + if (mt.isErroneous) setError(tree) + else errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) } else { val tparams = context.undetparams context.undetparams = List() @@ -1737,7 +1728,7 @@ trait Typers { self: Analyzer => protected def existentialBound(sym: Symbol): Type = if (sym.isClass) parameterizedType( - sym.typeParams, mkTypeBounds(AllClass.tpe, anonymousClassRefinement(sym))) + sym.typeParams, mkTypeBounds(AllClass.tpe, classBound(sym))) else if (sym.isAbstractType) sym.info else if (sym.isTerm) @@ -1772,7 +1763,7 @@ trait Typers { self: Analyzer => /** Compute an existential type from raw hidden symbols `syms' and type `tp' */ - def packSymbols(hidden: List[Symbol], tp: Type) = + def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else { // Console.println("original type: "+tp) @@ -1784,14 +1775,22 @@ trait Typers { self: Analyzer => res } + class SymInstance(val sym: Symbol, val tp: Type) { + override def equals(other: Any): Boolean = other match { + case that: SymInstance => + this.sym == that.sym && this.tp =:= that.tp + case _ => + false + } + override def hashCode: Int = sym.hashCode * 41 + tp.hashCode + } + def packedType(tree: Tree, owner: Symbol): Type = { def defines(tree: Tree, sym: Symbol) = sym.isExistentialSkolem && sym.unpackLocation == tree || tree.isDef && tree.symbol == sym - def isAnonymousFunction(sym: Symbol) = - (sym hasFlag SYNTHETIC) && (sym.name == nme.ANON_FUN_NAME) def isVisibleParameter(sym: Symbol) = - (sym hasFlag PARAM) && (sym.owner == owner) && (sym.isType || !isAnonymousFunction(owner)) + (sym hasFlag PARAM) && (sym.owner == owner) && (sym.isType || !owner.isAnonymousFunction) def containsDef(owner: Symbol, sym: Symbol): Boolean = (!(sym hasFlag PACKAGE)) && { var o = sym.owner @@ -1800,30 +1799,63 @@ trait Typers { self: Analyzer => } var localSyms = collection.immutable.Set[Symbol]() var boundSyms = collection.immutable.Set[Symbol]() + var localInstances = collection.immutable.Map[SymInstance, Symbol]() + // add all local symbols of `tp' to `localSyms' + // expanding higher-kinded types into individual copies for esach instance. def addLocals(tp: Type) { def isLocal(sym: Symbol): Boolean = if (owner == NoSymbol) tree exists (defines(_, sym)) else containsDef(owner, sym) - def addIfLocal(sym: Symbol) { - if (sym != NoSymbol && - !sym.isRefinementClass && - !(localSyms contains sym) && !(boundSyms contains sym) && - isLocal(sym)) { - localSyms += sym - addLocals(existentialBound(sym)) + def addIfLocal(sym: Symbol, tp: Type) { + if (sym != NoSymbol && !sym.isRefinementClass && isLocal(sym) && + !(localSyms contains sym) && !(boundSyms contains sym) ) { + if (sym.typeParams.isEmpty) { + localSyms += sym + addLocals(existentialBound(sym)) + } else if (tp.typeArgs.isEmpty) { + unit.error(tree.pos, + "implementation restriction: can't existentially abstract over higher-kinded type" + tp) + } else { + val inst = new SymInstance(sym, tp) + if (!(localInstances contains inst)) { + val bound = existentialBound(sym) match { + case PolyType(tparams, restpe) => + restpe.subst(tparams, tp.typeArgs) + case t => + t + } + val local = sym.owner.newAbstractType( + sym.pos, unit.fresh.newName(sym.name.toString)) + .setFlag(sym.flags) + .setInfo(bound) + localInstances += (inst -> local) + addLocals(bound) } + } + } } for (t <- tp) { t match { - case ExistentialType(tparams, _) => boundSyms ++= tparams + case ExistentialType(tparams, _) => + boundSyms ++= tparams case _ => } - addIfLocal(t.termSymbol) - addIfLocal(t.typeSymbol) + addIfLocal(t.termSymbol, t) + addIfLocal(t.typeSymbol, t) + } + } + val substLocals = new TypeMap { + def apply(t: Type): Type = t match { + case TypeRef(_, sym, args) if (sym.isLocal && args.length > 0) => + localInstances.get(new SymInstance(sym, t)) match { + case Some(local) => typeRef(NoPrefix, local, List()) + case None => mapOver(t) + } + case _ => mapOver(t) } } addLocals(tree.tpe) - packSymbols(localSyms.toList, tree.tpe) + packSymbols(localSyms.toList ::: localInstances.values.toList, substLocals(tree.tpe)) } protected def typedExistentialTypeTree(tree: ExistentialTypeTree): Tree = { @@ -2043,14 +2075,6 @@ trait Typers { self: Analyzer => errorTree(expr1, "_ must follow method; cannot follow " + expr1.tpe) } - def typedWildcardStar(expr1: Tree, tpt: Tree) = expr1.tpe.baseType(SeqClass) match { - case TypeRef(_, _, List(elemtp)) => - copy.Typed(tree, expr1, tpt setType elemtp) setType elemtp - case _ => - //todo: do this: errorTree(tree, "`: _*' annotation only legal for method arguments") - setError(tree) - } - def typedTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match { case OverloadedType(pre, alts) => inferPolyAlternatives(fun, args map (_.tpe)) @@ -2074,11 +2098,14 @@ trait Typers { self: Analyzer => Literal(Constant(targs.head)) setPos tree.pos setType Predef_classOfType(targs.head) // @M: targs.head.normalize is not necessary --> toTypeKind eventually normalizes the type } else { + if (phase.id <= currentRun.typerPhase.id && + fun.symbol == Any_isInstanceOf && !targs.isEmpty) + checkCheckable(tree.pos, targs.head, "") val resultpe0 = restpe.instantiateTypeParams(tparams, targs) //@M TODO -- probably ok //@M example why asSeenFrom is necessary: class Foo[a] { def foo[m[x]]: m[a] } (new Foo[Int]).foo[List] : List[Int] //@M however, asSeenFrom widens a singleton type, thus cannot use it for those types - val resultpe = if(resultpe0.isInstanceOf[SingletonType]) resultpe0 else resultpe0.asSeenFrom(prefixType(fun), fun.symbol.owner) + val resultpe = if (resultpe0.isInstanceOf[SingletonType]) resultpe0 else resultpe0.asSeenFrom(prefixType(fun), fun.symbol.owner) copy.TypeApply(tree, fun, args) setType resultpe } } else { @@ -2394,6 +2421,10 @@ trait Typers { self: Analyzer => var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope var cx = context + if ((mode & PATTERNmode) != 0) + // ignore current variable scope in patterns to enforce linearity + cx = cx.outer + while (defSym == NoSymbol && cx != NoContext) { pre = cx.enclClass.prefix defEntry = cx.scope.lookupEntry(name) @@ -2602,6 +2633,11 @@ trait Typers { self: Analyzer => case Bind(name, body) => typedBind(name, body) + case UnApply(fun, args) => + val fun1 = typed(fun) + val args1 = List.mapConserve(args)(typedPattern(_, WildcardType)) + copy.UnApply(tree, fun1, args1) setType pt + case ArrayValue(elemtpt, elems) => typedArrayValue(elemtpt, elems) @@ -2654,7 +2690,13 @@ trait Typers { self: Analyzer => typedEta(checkDead(typed1(expr, mode, pt))) case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) => - typedWildcardStar(typed(expr, mode & stickyModes, seqType(pt)), tpt) + val expr1 = typed(expr, mode & stickyModes, seqType(pt)) + expr1.tpe.baseType(SeqClass) match { + case TypeRef(_, _, List(elemtp)) => + copy.Typed(tree, expr1, tpt setType elemtp) setType elemtp + case _ => + setError(tree) + } case Typed(expr, tpt) => val tpt1 = typedType(tpt) diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 8236a06bfd..bed77fcc64 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -15,12 +15,6 @@ package scala.collection.immutable object TreeSet { - /** The empty set of this type - * @deprecated use empty instead - */ - @deprecated - def Empty[A <% Ordered[A]] = empty[A] - /** The empty set of this type */ def empty[A <% Ordered[A]] = new TreeSet[A] diff --git a/test/files/neg/bug835.check b/test/files/neg/bug835.check index 83db589280..79ea97b71f 100644 --- a/test/files/neg/bug835.check +++ b/test/files/neg/bug835.check @@ -1,4 +1,9 @@ -bug835.scala:2: error: _*-argument may not appear after other arguments matching a *-parameter +bug835.scala:2: error: no `: _*' annotation allowed here +(such annotations are only allowed in arguments to *-parameters) + Console.println(List(List(1, 2, 3) : _*, List(4, 5, 6) : _*)) + ^ +bug835.scala:2: error: no `: _*' annotation allowed here +(such annotations are only allowed in arguments to *-parameters) Console.println(List(List(1, 2, 3) : _*, List(4, 5, 6) : _*)) ^ -one error found +two errors found diff --git a/test/files/neg/bug875.check b/test/files/neg/bug875.check index 63ad0f7eb0..d547c8d69c 100644 --- a/test/files/neg/bug875.check +++ b/test/files/neg/bug875.check @@ -1,13 +1,17 @@ -bug875.scala:3: error: _*-argument may not appear after other arguments matching a *-parameter +bug875.scala:3: error: no `: _*' annotation allowed here +(such annotations are only allowed in arguments to *-parameters) val ys = List(1, 2, 3, xs: _*) ^ -bug875.scala:6: error: _*-argument does not correspond to *-parameter +bug875.scala:6: error: no `: _*' annotation allowed here +(such annotations are only allowed in arguments to *-parameters) mkList(xs: _*) ^ -bug875.scala:15: error: _*-argument may not appear after other arguments matching a *-parameter +bug875.scala:15: error: no `: _*' annotation allowed here +(such annotations are only allowed in arguments to *-parameters) f(true, 1, xs: _*) ^ -bug875.scala:16: error: _*-argument may not appear after other arguments matching a *-parameter +bug875.scala:16: error: no `: _*' annotation allowed here +(such annotations are only allowed in arguments to *-parameters) g(1, xs:_*) ^ four errors found diff --git a/test/files/pos/bug602.scala b/test/files/pos/bug602.scala index 60aef1dfd0..5877d08ddc 100644 --- a/test/files/pos/bug602.scala +++ b/test/files/pos/bug602.scala @@ -1,6 +1,10 @@ package com.mosol.sl; case class Span[K <: Ordered[K]](low: Option[K], high: Option[K]) extends Function1[K, boolean] { + override def equals(x$1: Any): Boolean = x$1 match { + case Span((low$0 @ _), (high$0 @ _)) if low$0.equals(low).$amp$amp(high$0.equals(high)) => true + case _ => false + } def apply(k: K): boolean = this match { case Span(Some(low), Some(high)) => (k >= low && k <= high) case Span(Some(low), None) => (k >= low) diff --git a/test/files/run/existentials.scala b/test/files/run/existentials.scala index a08a9da9b3..9dc9855a75 100755 --- a/test/files/run/existentials.scala +++ b/test/files/run/existentials.scala @@ -52,6 +52,9 @@ object Bug1189 { object Test extends Application { + val x = { class I[T]; (new C(new I[String]), new C(new I[Int])) } + val y: (C[X], C[Y]) forSome { type X; type Y } = x + def foo(x : Counter[T] { def name : String } forSome { type T }) = x match { case ctr: Counter[t] => val c = ctr.newCounter diff --git a/test/files/run/regularpatmatnew.scala b/test/files/run/regularpatmatnew.scala index 0457cd6d6c..c610b80444 100644 --- a/test/files/run/regularpatmatnew.scala +++ b/test/files/run/regularpatmatnew.scala @@ -105,7 +105,7 @@ object Test { case Bar(xs@_*) => xs // this should be optimized away to a pattern Bar(xs) case _ => Nil } - assertEquals("res instance"+res.isInstanceOf[Seq[Con]]+" res(0)="+res(0), true, res.isInstanceOf[Seq[Foo]] && res(0) == Foo() ) + assertEquals("res instance"+res.isInstanceOf[Seq[Con] forSome { type Con }]+" res(0)="+res(0), true, res.isInstanceOf[Seq[Foo] forSome { type Foo}] && res(0) == Foo() ) } } diff --git a/test/files/run/withIndex.check b/test/files/run/withIndex.check index 6a9c7aaadb..e8060bb1d7 100644 --- a/test/files/run/withIndex.check +++ b/test/files/run/withIndex.check @@ -1,3 +1,5 @@ +warning: there were unchecked warnings; re-run with -unchecked for details +one warning found List((a,0), (b,1), (c,2)) List((a,0), (b,1), (c,2)) List((a,0), (b,1), (c,2)) diff --git a/test/files/run/withIndex.scala b/test/files/run/withIndex.scala index fd79cd808a..d06dde89f0 100644 --- a/test/files/run/withIndex.scala +++ b/test/files/run/withIndex.scala @@ -9,7 +9,12 @@ object Test { Console.println(lst.zipWithIndex.toList) Console.println(itr.zipWithIndex.toList) Console.println(str.zipWithIndex.toList) - assert(ary.zipWithIndex.isInstanceOf[Array[Pair[String,Int]]]) + assert { + ary.zipWithIndex match { + case _: Array[Pair[String,Int]] => true + case _ => false + } + } val emptyArray = new Array[String](0) val emptyList: List[String] = Nil -- cgit v1.2.3