From 247577e9664407de2f98294a2adae6f8131d919d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 30 Oct 2006 18:20:03 +0000 Subject: fixed bug421 --- .../scala/tools/nsc/symtab/Definitions.scala | 10 ++--- .../scala/tools/nsc/typechecker/Infer.scala | 5 ++- .../scala/tools/nsc/typechecker/Typers.scala | 47 +++++++++++++++++----- test/files/neg/bug421.check | 7 ++-- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 630fd2cef3..ff67a62b3c 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -156,11 +156,11 @@ trait Definitions requires SymbolTable { } def unapplySeqResultToMethodSig(tp: Type) = { - val xs = optionOfProductElems(tp).reverse - (xs.head.baseType(SeqClass) match { - case TypeRef(pre, seqClass, args) => - typeRef(pre, RepeatedParamClass, args) :: xs.tail - }).reverse + val ts = optionOfProductElems(tp) + val last1 = ts.last.baseType(SeqClass) match { + case TypeRef(pre, seqClass, args) => typeRef(pre, RepeatedParamClass, args) + } + ts.init ::: List(last1) } /* */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index d9ea1b9916..476fefac7d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -29,6 +29,9 @@ trait Infer requires Analyzer { def assertNonCyclic(tvar: TypeVar) = assert(tvar.constr.inst != tvar, tvar.origin) + def isVarArgs(formals: List[Type]) = + !formals.isEmpty && (formals.last.symbol == RepeatedParamClass) + /** The formal parameter types corresponding to formals. * If formals has a repeated last parameter, a list of * (nargs - params.length + 1) copies of its type is returned. @@ -41,7 +44,7 @@ trait Infer requires Analyzer { case TypeRef(_, sym, List(arg)) if (sym == ByNameParamClass) => arg case formal => formal } - if (!formals1.isEmpty && (formals1.last.symbol == RepeatedParamClass)) { + if (isVarArgs(formals1)) { val ft = formals1.last.typeArgs.head formals1.init ::: (for (val i <- List.range(formals1.length - 1, nargs)) yield ft) } else formals1 diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 3e3193f964..6b76f71b6f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -111,6 +111,11 @@ trait Typers requires Analyzer { */ val CONSTmode = 0x800 + /** The mode REGPATmode is set when regular expression patterns + * are allowed. + */ + val REGPATmode = 0x1000 + class Typer(context0: Context) { import context0.unit @@ -254,6 +259,12 @@ trait Typers requires Analyzer { case _ => } + def checkRegPatOK(pos: PositionType, mode: int): unit = + 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. */ @@ -1191,14 +1202,28 @@ trait Typers requires Analyzer { checkNoDoubleDefs(List.mapConserve(stats)(typedStat)) } - def typedArg(arg: Tree, mode: int, pt: Type): Tree = { + def typedArg(arg: Tree, mode: int, newmode: int, pt: Type): Tree = { val argTyper = if ((mode & SCCmode) != 0) newTyper(context.makeConstructorContext) else this - argTyper.typed(arg, mode & (stickyModes | POLYmode), pt) + argTyper.typed(arg, mode & stickyModes | newmode, pt) } def typedArgs(args: List[Tree], mode: int) = - List.mapConserve(args)(arg => typedArg(arg, mode, WildcardType)) + List.mapConserve(args)(arg => typedArg(arg, mode, 0, WildcardType)) + + def typedArgs(args: List[Tree], mode: int, originalFormals: List[Type], adaptedFormals: List[Type]) = + if ((mode & PATTERNmode) != 0 && isVarArgs(originalFormals)) { + val nonVarCount = originalFormals.length - 1 + val prefix = + List.map2(args take nonVarCount, adaptedFormals take nonVarCount) ((arg, formal) => + typedArg(arg, mode, 0, formal)) + val suffix = + List.map2(args drop nonVarCount, adaptedFormals drop nonVarCount) ((arg, formal) => + typedArg(arg, mode, REGPATmode, formal)) + prefix ::: suffix + } else { + List.map2(args, adaptedFormals)((arg, formal) => typedArg(arg, mode, 0, formal)) + } def typedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: int, pt: Type): Tree = { var fun = fun0; @@ -1224,8 +1249,7 @@ trait Typers requires Analyzer { val tparams = context.undetparams context.undetparams = List() if (tparams.isEmpty) { - val args1 = List.map2(args, formals)((arg, formal) => - typedArg(arg, mode, formal)) + val args1 = typedArgs(args, mode, formals0, formals) def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp case _ => tp @@ -1253,7 +1277,7 @@ trait Typers requires Analyzer { if (targ == WildcardType) tparam.tpe else targ) def typedArgToPoly(arg: Tree, formal: Type): Tree = { val lenientPt = formal.subst(tparams, lenientTargs) - val arg1 = typedArg(arg, mode | POLYmode, lenientPt) + val arg1 = typedArg(arg, mode, POLYmode, lenientPt) val argtparams = context.undetparams context.undetparams = List() if (!argtparams.isEmpty) { @@ -1316,11 +1340,10 @@ trait Typers requires Analyzer { val fun1 = typed(atPos(fun.pos) { Apply(Select(Ident(fun.symbol), unapp), List(arg)) }, EXPRmode, funPt) if (fun1.tpe.isErroneous) setError(tree) else { - var argPts = if(unapp.name == nme.unapply) optionOfProductElems(fun1.tpe) - else unapplySeqResultToMethodSig(fun1.tpe) - argPts = formalTypes(argPts, args.length) - - val args1 = List.map2(args, argPts)((arg, formal) => typedArg(arg, mode, formal)) + var formals0 = if(unapp.name == nme.unapply) optionOfProductElems(fun1.tpe) + else unapplySeqResultToMethodSig(fun1.tpe) + val formals1 = formalTypes(formals0, args.length) + val args1 = typedArgs(args, mode, formals0, formals1) UnApply(fun1, args1) setPos tree.pos setType pt } /* --- end unapply --- */ @@ -1736,6 +1759,7 @@ trait Typers requires Analyzer { .typedBlock(tree, mode, pt) case Sequence(elems) => + checkRegPatOK(tree.pos, mode) val elems1 = List.mapConserve(elems)(elem => typed(elem, mode, pt)) copy.Sequence(tree, elems1) setType pt @@ -1744,6 +1768,7 @@ trait Typers requires Analyzer { copy.Alternative(tree, alts1) setType pt case Star(elem) => + checkRegPatOK(tree.pos, mode) val elem1 = typed(elem, mode, pt) copy.Star(tree, elem1) setType pt diff --git a/test/files/neg/bug421.check b/test/files/neg/bug421.check index eafd421ad4..5ae34358b1 100644 --- a/test/files/neg/bug421.check +++ b/test/files/neg/bug421.check @@ -1,4 +1,5 @@ -bug421.scala:4 error: regular expressions not yet implemented - Bar("foo","meets","bar") match { - ^ +bug421.scala:5 error: no regular expression pattern allowed here +(regular expression patterns are only allowed in arguments to *-parameters) + case Bar("foo",_*) => error("huh?"); + ^ one error found -- cgit v1.2.3