From aa6723c500b5c226a68609418f98f94adab7a8bf Mon Sep 17 00:00:00 2001 From: Eugene Vigdorchik Date: Sun, 7 Apr 2013 14:07:05 +0400 Subject: SI-7329 duplicate default getters for specialized parameters. The default getter is generated with @specialized annotation if the type parameter corresponding to the type of the parameter is specialized. Consequently specialize pass tries to generate overloads. Rather than pruning overloads to exclude duplicates, let's notice that default getter specialization is not needed at all: - The dynamic scope of default getter doesn't include specialized method or class constructor. - generic default getter is called even when calling specialized method: object V { @specialized def foo[@specialized B](b: B = (??? : B)) = {} foo[Int]() } gives: invokevirtual Method V$.foo$default$1:()Ljava/lang/Object; invokestatic (unboxToInt) invokevirtual Method V$.foo$mIc$sp:(I)V --- test/files/pos/t7329.scala | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/files/pos/t7329.scala (limited to 'test') diff --git a/test/files/pos/t7329.scala b/test/files/pos/t7329.scala new file mode 100644 index 0000000000..76bf1fb9f5 --- /dev/null +++ b/test/files/pos/t7329.scala @@ -0,0 +1 @@ +class TwoParamSpecializedWithDefault[@specialized A, @specialized B](a: A, b: B = (??? : B)) \ No newline at end of file -- cgit v1.2.3 From ef04619e3032dd513bf2e219a03ecf53e8dc8ce6 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 1 Apr 2013 11:37:57 +0200 Subject: SI-7319 Clear error buffer during Typer reset. Contexts share error/warning buffers with their children, and this also applies ot the shared `startContext`. That context flushes the buffers in `startContext` in `resetContexts`. It also removes `typerReportAnyContextErrors`, which appears to be an elaborate no-op. It is only ever passed a context `c` which is a direct child of `this.context`. So taking a buffered error out of `c` and reissuing it into `this.context` merely re-inserts into into the same error buffer. Consrast this with `silent`, which uses a child context with a fresh error buffer. SI-7319 Flush error buffer in typerReportAnyContextErrors. After this change, we no longer rely on the backstop in resetContexts introduced in the previous commit. --- .../scala/tools/nsc/typechecker/Contexts.scala | 2 ++ .../scala/tools/nsc/typechecker/Typers.scala | 30 +++++++---------- test/files/run/t7319.check | 38 ++++++++++++++++++++++ test/files/run/t7319.scala | 13 ++++++++ 4 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 test/files/run/t7319.check create mode 100644 test/files/run/t7319.scala (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index f2a2ef4d61..6c2945cad3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -84,6 +84,8 @@ trait Contexts { self: Analyzer => case Import(qual, _) => qual.tpe = singleType(qual.symbol.owner.thisType, qual.symbol) case _ => } + sc.flushAndReturnBuffer() + sc.flushAndReturnWarningsBuffer() sc = sc.outer } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d1d6feae97..d3e9192066 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -507,10 +507,7 @@ trait Typers extends Modes with Adaptations with Tags { @inline final def typerReportAnyContextErrors[T](c: Context)(f: Typer => T): T = { - val res = f(newTyper(c)) - if (c.hasErrors) - context.issue(c.errBuffer.head) - res + f(newTyper(c)) } @inline @@ -1747,9 +1744,7 @@ trait Typers extends Modes with Adaptations with Tags { assert(clazz != NoSymbol, cdef) reenterTypeParams(cdef.tparams) val tparams1 = cdef.tparams mapConserve (typedTypeDef) - val impl1 = typerReportAnyContextErrors(context.make(cdef.impl, clazz, newScope)) { - _.typedTemplate(cdef.impl, parentTypes(cdef.impl)) - } + val impl1 = newTyper(context.make(cdef.impl, clazz, newScope)).typedTemplate(cdef.impl, parentTypes(cdef.impl)) val impl2 = finishMethodSynthesis(impl1, clazz, context) if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass) checkEphemeral(clazz, impl2.body) @@ -1790,17 +1785,16 @@ trait Typers extends Modes with Adaptations with Tags { || !linkedClass.isSerializable || clazz.isSerializable ) - val impl1 = typerReportAnyContextErrors(context.make(mdef.impl, clazz, newScope)) { - _.typedTemplate(mdef.impl, { - parentTypes(mdef.impl) ++ ( - if (noSerializable) Nil - else { - clazz.makeSerializable() - List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus) - } - ) - }) - } + val impl1 = newTyper(context.make(mdef.impl, clazz, newScope)).typedTemplate(mdef.impl, { + parentTypes(mdef.impl) ++ ( + if (noSerializable) Nil + else { + clazz.makeSerializable() + List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus) + } + ) + }) + val impl2 = finishMethodSynthesis(impl1, clazz, context) // SI-5954. On second compile of a companion class contained in a package object we end up diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check new file mode 100644 index 0000000000..966736915e --- /dev/null +++ b/test/files/run/t7319.check @@ -0,0 +1,38 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> class M[A] +defined class M + +scala> implicit def ma0[A](a: A): M[A] = null +warning: there were 1 feature warning(s); re-run with -feature for details +ma0: [A](a: A)M[A] + +scala> implicit def ma1[A](a: A): M[A] = null +warning: there were 1 feature warning(s); re-run with -feature for details +ma1: [A](a: A)M[A] + +scala> def convert[F[X <: F[X]]](builder: F[_ <: F[_]]) = 0 +warning: there were 1 feature warning(s); re-run with -feature for details +convert: [F[X <: F[X]]](builder: F[_ <: F[_]])Int + +scala> convert(Some[Int](0)) +:12: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : Some[Int] + required: ?F forSome { type _$1 <: ?F forSome { type _$2 } } + convert(Some[Int](0)) + ^ +:12: error: type mismatch; + found : Some[Int] + required: F[_ <: F[_]] + convert(Some[Int](0)) + ^ + +scala> 0 +res1: Int = 0 + +scala> diff --git a/test/files/run/t7319.scala b/test/files/run/t7319.scala new file mode 100644 index 0000000000..23ffeb977d --- /dev/null +++ b/test/files/run/t7319.scala @@ -0,0 +1,13 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + // so we can provide the ambiguities, rather than relying in Predef implicits + override def extraSettings = "-Yno-predef" + override def code = """ +class M[A] +implicit def ma0[A](a: A): M[A] = null +implicit def ma1[A](a: A): M[A] = null +def convert[F[X <: F[X]]](builder: F[_ <: F[_]]) = 0 +convert(Some[Int](0)) +0""" // before the fix, this line, and all that followed, re-issued the implicit ambiguity error. +} -- cgit v1.2.3 From 15e9ef8f083e0c0dc75bf51a0784f56df2e2bea8 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 17 Apr 2013 09:19:21 +0200 Subject: SI-7377 Fix retypechecking of patterns on case companion alias Some ancient code in Typers switches from PATTERNmode to EXPRmode when encountering `stableF(...)`. It just typechecks `stableF` and discards the arguments. To the best of Martin's recollection, this has something to do with the need to typecheck patterns rather late in the compiler, after `a.b` had been translated to `a.b()` in `Uncurry`. I'm not able to motivate this with tests using `-Xoldpatmat`; was there ever an even older pattern matcher that ran *after* uncurry? What changed in 2.10.1 to expose this wrinkle? dfbaaa17 fixed `TypeTree.copyAttrs` to copy the original tree. During the descent of `ResetAttrs`, sub-trees are duplicated before begin further transformed. Duplicating the `Match` in 2.10.0 would forget that the original tree of: pat = (a: Int)Foo(_) `----------` `- TypeTree((a: Int)Foo), with original Select(..., "FooAlias") The retypechecking would operate on the `MethodType`, rather than the `Select`, which was not considered a stable application. For 2.10.x, I've just tightened up the condition to only hit this if `args` is empty. I'm almost certain that the code can be removed altogether, and I'll do that when this is merged to master. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 7 ++++++- test/files/pos/t7377/Client_2.scala | 11 +++++++++++ test/files/pos/t7377/Macro_1.scala | 7 +++++++ test/files/pos/t7377b.flags | 1 + test/files/pos/t7377b.scala | 13 +++++++++++++ 5 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/t7377/Client_2.scala create mode 100644 test/files/pos/t7377/Macro_1.scala create mode 100644 test/files/pos/t7377b.flags create mode 100644 test/files/pos/t7377b.scala (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d1d6feae97..33f60d6676 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4532,8 +4532,13 @@ trait Typers extends Modes with Adaptations with Tags { def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = { val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable - if (stableApplication && isPatternMode) { + if (args.isEmpty && stableApplication && isPatternMode) { // treat stable function applications f() as expressions. + // + // [JZ] According to Martin, this is related to the old pattern matcher, which + // needs to typecheck after a the translation of `x.f` to `x.f()` in a prior + // compilation phase. As part of SI-7377, this has been tightened with `args.isEmpty`, + // but we should remove it altogether in Scala 2.11. typed1(tree, mode & ~PATTERNmode | EXPRmode, pt) } else { val funpt = if (isPatternMode) pt else WildcardType diff --git a/test/files/pos/t7377/Client_2.scala b/test/files/pos/t7377/Client_2.scala new file mode 100644 index 0000000000..5728956cca --- /dev/null +++ b/test/files/pos/t7377/Client_2.scala @@ -0,0 +1,11 @@ +object Test { + M.noop(List(1) match { case Nil => 0; case (x::xs) => x }) + + case class Foo(a: Int) + val FooAlias: Foo.type = Foo + M.noop(Foo(0) match { case FooAlias(_) => 0 }) + + case class Bar() + val BarAlias: Bar.type = Bar + M.noop(Bar() match { case BarAlias() => 0 }) +} diff --git a/test/files/pos/t7377/Macro_1.scala b/test/files/pos/t7377/Macro_1.scala new file mode 100644 index 0000000000..a0ec1d84af --- /dev/null +++ b/test/files/pos/t7377/Macro_1.scala @@ -0,0 +1,7 @@ +import language.experimental._ +import reflect.macros.Context + +object M { + def noopImpl[A](c: Context)(expr: c.Expr[A]): c.Expr[A] = c.Expr(c.typeCheck(c.resetLocalAttrs(expr.tree))) + def noop[A](expr: A): A = macro noopImpl[A] +} diff --git a/test/files/pos/t7377b.flags b/test/files/pos/t7377b.flags new file mode 100644 index 0000000000..cb8324a345 --- /dev/null +++ b/test/files/pos/t7377b.flags @@ -0,0 +1 @@ +-Xoldpatmat \ No newline at end of file diff --git a/test/files/pos/t7377b.scala b/test/files/pos/t7377b.scala new file mode 100644 index 0000000000..aeee800d57 --- /dev/null +++ b/test/files/pos/t7377b.scala @@ -0,0 +1,13 @@ +object Test { + List(1) match { case Nil => 0; case (x::xs) => x } + + case class Foo(a: Int) + val FooAlias: Foo.type = Foo + Foo(0) match { case FooAlias(_) => 0 } + Foo(0) match { case Foo(_) => 0 } + + case class Bar() + val BarAlias: Bar.type = Bar + Bar() match { case BarAlias() => 0 } + Bar() match { case Bar() => 0 } +} -- cgit v1.2.3 From 351d5ec22688a48227b76f417a0dd520934d98d7 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 17 Apr 2013 14:01:50 -0700 Subject: Absolute path in error message. As soon as you have a directory called "language" lying around, you will appreciate why the advice given regarding SIP-18 should be "import scala.language..." not "import language..." --- .../scala/tools/nsc/typechecker/Typers.scala | 21 ++++++++++++--------- test/files/neg/macro-without-xmacros-a.check | 6 +++--- test/files/neg/macro-without-xmacros-b.check | 6 +++--- test/files/neg/t6040.check | 2 +- test/files/neg/t6952.check | 4 ++-- 5 files changed, 21 insertions(+), 18 deletions(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d1d6feae97..51458de280 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -780,16 +780,19 @@ trait Typers extends Modes with Adaptations with Tags { if (!OK) { val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) = featureTrait getAnnotation LanguageFeatureAnnot - val req = if (required) "needs to" else "should" - var raw = featureDesc + " " + req + " be enabled\n" + - "by making the implicit value language." + featureName + " visible." - if (!(currentRun.reportedFeature contains featureTrait)) - raw += "\nThis can be achieved by adding the import clause 'import scala.language." + featureName + "'\n" + - "or by setting the compiler option -language:" + featureName + ".\n" + - "See the Scala docs for value scala.language." + featureName + " for a discussion\n" + - "why the feature " + req + " be explicitly enabled." + val req = if (required) "needs to" else "should" + val fqname = "scala.language." + featureName + val explain = ( + if (currentRun.reportedFeature contains featureTrait) "" else + s"""| + |This can be achieved by adding the import clause 'import $fqname' + |or by setting the compiler option -language:$featureName. + |See the Scala docs for value $fqname for a discussion + |why the feature $req be explicitly enabled.""".stripMargin + ) currentRun.reportedFeature += featureTrait - val msg = raw replace ("#", construct) + + val msg = s"$featureDesc $req be enabled\nby making the implicit value $fqname visible.$explain" replace ("#", construct) if (required) unit.error(pos, msg) else currentRun.featureWarnings.warn(pos, msg) } diff --git a/test/files/neg/macro-without-xmacros-a.check b/test/files/neg/macro-without-xmacros-a.check index ae6c6c695a..ec194be3a9 100644 --- a/test/files/neg/macro-without-xmacros-a.check +++ b/test/files/neg/macro-without-xmacros-a.check @@ -1,5 +1,5 @@ Macros_2.scala:5: error: macro definition needs to be enabled -by making the implicit value language.experimental.macros visible. +by making the implicit value scala.language.experimental.macros visible. This can be achieved by adding the import clause 'import scala.language.experimental.macros' or by setting the compiler option -language:experimental.macros. See the Scala docs for value scala.language.experimental.macros for a discussion @@ -7,11 +7,11 @@ why the feature needs to be explicitly enabled. def foo(x: Int): Int = macro foo_impl ^ Macros_2.scala:7: error: macro definition needs to be enabled -by making the implicit value language.experimental.macros visible. +by making the implicit value scala.language.experimental.macros visible. def bar(x: Int): Int = macro bar_impl ^ Macros_2.scala:11: error: macro definition needs to be enabled -by making the implicit value language.experimental.macros visible. +by making the implicit value scala.language.experimental.macros visible. def quux(x: Int): Int = macro quux_impl ^ three errors found diff --git a/test/files/neg/macro-without-xmacros-b.check b/test/files/neg/macro-without-xmacros-b.check index c3cadcf36a..c97850f0a9 100644 --- a/test/files/neg/macro-without-xmacros-b.check +++ b/test/files/neg/macro-without-xmacros-b.check @@ -1,5 +1,5 @@ Macros_2.scala:3: error: macro definition needs to be enabled -by making the implicit value language.experimental.macros visible. +by making the implicit value scala.language.experimental.macros visible. This can be achieved by adding the import clause 'import scala.language.experimental.macros' or by setting the compiler option -language:experimental.macros. See the Scala docs for value scala.language.experimental.macros for a discussion @@ -7,11 +7,11 @@ why the feature needs to be explicitly enabled. def foo(x: Int): Int = macro Impls.foo_impl ^ Macros_2.scala:5: error: macro definition needs to be enabled -by making the implicit value language.experimental.macros visible. +by making the implicit value scala.language.experimental.macros visible. def bar(x: Int): Int = macro Impls.bar_impl ^ Macros_2.scala:9: error: macro definition needs to be enabled -by making the implicit value language.experimental.macros visible. +by making the implicit value scala.language.experimental.macros visible. def quux(x: Int): Int = macro Impls.quux_impl ^ three errors found diff --git a/test/files/neg/t6040.check b/test/files/neg/t6040.check index f91df0c46d..16c90ede7e 100644 --- a/test/files/neg/t6040.check +++ b/test/files/neg/t6040.check @@ -1,5 +1,5 @@ t6040.scala:1: error: extension of type scala.Dynamic needs to be enabled -by making the implicit value language.dynamics visible. +by making the implicit value scala.language.dynamics visible. This can be achieved by adding the import clause 'import scala.language.dynamics' or by setting the compiler option -language:dynamics. See the Scala docs for value scala.language.dynamics for a discussion diff --git a/test/files/neg/t6952.check b/test/files/neg/t6952.check index f1e1881404..1a591d02c6 100644 --- a/test/files/neg/t6952.check +++ b/test/files/neg/t6952.check @@ -1,5 +1,5 @@ t6952.scala:2: error: extension of type scala.Dynamic needs to be enabled -by making the implicit value language.dynamics visible. +by making the implicit value scala.language.dynamics visible. This can be achieved by adding the import clause 'import scala.language.dynamics' or by setting the compiler option -language:dynamics. See the Scala docs for value scala.language.dynamics for a discussion @@ -7,7 +7,7 @@ why the feature needs to be explicitly enabled. trait B extends Dynamic ^ t6952.scala:3: error: extension of type scala.Dynamic needs to be enabled -by making the implicit value language.dynamics visible. +by making the implicit value scala.language.dynamics visible. trait C extends A with Dynamic ^ two errors found -- cgit v1.2.3 From 3e27fec3cf44bcc523fea6bac39ac9b99b438393 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 18 Apr 2013 23:38:15 +0200 Subject: SI-7388 Be more robust against cycles in error symbol creation. `Symbol#toString` was triggering `CyclicReferenceError` (specifically, `accurateKindString` which calls `owner.primaryConstructor`.) The `toString` output is used when creating an error symbol to assign to the tree after an error (in this case, a non-existent access qualifier.) This commit catches the error, and falls back to just using the symbol's name. --- src/compiler/scala/tools/nsc/typechecker/Infer.scala | 6 +++++- test/files/neg/t7388.check | 4 ++++ test/files/neg/t7388.scala | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t7388.check create mode 100644 test/files/neg/t7388.scala (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 7161043dcf..7dd182e3ee 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -286,7 +286,11 @@ trait Infer extends Checkable { // println("set error: "+tree); // throw new Error() // } - def name = newTermName("") + def name = { + val sym = tree.symbol + val nameStr = try sym.toString catch { case _: CyclicReference => sym.nameString } + newTermName(s"") + } def errorClass = if (context.reportErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass def errorValue = if (context.reportErrors) context.owner.newErrorValue(name) else stdErrorValue def errorSym = if (tree.isType) errorClass else errorValue diff --git a/test/files/neg/t7388.check b/test/files/neg/t7388.check new file mode 100644 index 0000000000..0a29e04896 --- /dev/null +++ b/test/files/neg/t7388.check @@ -0,0 +1,4 @@ +t7388.scala:1: error: doesnotexist is not an enclosing class +class Test private[doesnotexist]() + ^ +one error found diff --git a/test/files/neg/t7388.scala b/test/files/neg/t7388.scala new file mode 100644 index 0000000000..9ce9ea11b3 --- /dev/null +++ b/test/files/neg/t7388.scala @@ -0,0 +1 @@ +class Test private[doesnotexist]() -- cgit v1.2.3