diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2016-01-29 17:56:21 -0800 |
---|---|---|
committer | Stefan Zeiger <szeiger@novocode.com> | 2016-03-07 17:27:49 +0100 |
commit | e7e1c77092ec0d64a6ecbb8b920d1b4cca74837f (patch) | |
tree | fe490f451d0960b77045c621d7aa2b462288e119 /src/reflect | |
parent | a926b840e1e756c0dcd936499583ed19d357b97b (diff) | |
download | scala-e7e1c77092ec0d64a6ecbb8b920d1b4cca74837f.tar.gz scala-e7e1c77092ec0d64a6ecbb8b920d1b4cca74837f.tar.bz2 scala-e7e1c77092ec0d64a6ecbb8b920d1b4cca74837f.zip |
Improved outer ref checking in pattern matches:
The old algorithm omitted necessary outer ref checks in some places.
This new one is more conservative. It only omits outer ref checks when
the expected type and the scrutinee type match up, or when the expected
type is defined in a static location. For this specific purpose the top
level of a method or other code block (which is not a trait or class
definition) is also considered static because it does not have a prefix.
This change comes with a spec update to clarify the prefix rule for type
patterns. The new wording makes it clear that the presence of a prefix
is to be interpreted in a *semantic* way, i.e. the existence of a prefix
determines the necessity for an outer ref check, no matter if the prefix
is actually spelled out *syntactically*. Note that the old outer ref
check implementation did not use the alternative interpretation of
requiring prefixes to be given syntactically. It never created an outer
ref check for a local class `C`, no matter if the pattern was `_: C`
or `_: this.C`, thus violating both interpretations of the spec.
There is now explicit support for unchecked matches (like
`case _: (T @unchecked) =>`) to suppress warnings for unchecked outer
refs. `@unchecked` worked before and was used for this purpose in
`neg/t7721` but never actually existed as a feature. It was a result of
a bug that prevented an outer ref check from being generated in the
first place if *any* annotation was used on an expected type in a type
pattern. This new version will still generate the outer ref check if an
outer ref is available but suppress the warning otherwise. Other
annotations on type patterns are ignored.
New tests are in `neg/outer-ref-checks`. The expected results of tests
`neg/t7171` and `neg/t7171b` have changed because the compiler now
tries to generate additional outer ref checks that were not present
before (which was a bug).
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeGen.scala | 24 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 41 |
2 files changed, 24 insertions, 41 deletions
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 2933aa3892..ec6426558c 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -117,6 +117,30 @@ abstract class TreeGen { case _ => qual } + + + // val selType = testedBinder.info + // + // // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` + // // generates an outer test based on `patType.prefix` with automatically dealises. + // // Prefixes can have all kinds of shapes SI-9110 + // val patPre = expectedTp.dealiasWiden.prefix + // val selPre = selType.dealiasWiden.prefix + // + // // Optimization: which prefixes can we disqualify from the need for an outer reference check? + // // - classes in static owners do not get outer pointers + // // - if the prefixes are statically known to be equal, the type system ensures an outer test is redundant + // !((patPre eq NoPrefix) || (selPre eq NoPrefix) + // || patPre.typeSymbol.isPackageClass + // || selPre =:= patPre) + + def mkAttributedQualifierIfPossible(prefix: Type): Option[Tree] = prefix match { + case NoType | NoPrefix | ErrorType => None + case TypeRef(_, sym, _) if sym.isModule || sym.isClass || sym.isType => None + case pre => Some(mkAttributedQualifier(prefix)) + } + + /** Builds a reference to given symbol with given stable prefix. */ def mkAttributedRef(pre: Type, sym: Symbol): RefTree = { val qual = mkAttributedQualifier(pre) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 685c9f7476..24709cf379 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3946,47 +3946,6 @@ trait Types check(tp1, tp2) && check(tp2, tp1) } - /** Does a pattern of type `patType` need an outer test when executed against - * selector type `selType` in context defined by `currentOwner`? - */ - def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { - def createDummyClone(pre: Type): Type = { - val dummy = currentOwner.enclClass.newValue(nme.ANYname).setInfo(pre.widen) - singleType(ThisType(currentOwner.enclClass), dummy) - } - def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { - case SingleType(pre1, sym1) => - if (sym1.isModule && sym1.isStatic) { - if (sym.owner == sym1 || sym.isJavaDefined || sym.owner.sourceModule.isStaticModule) NoType - else pre - } else if (sym1.isModule && sym.owner == sym1.moduleClass) { - val pre2 = maybeCreateDummyClone(pre1, sym1) - if (pre2 eq NoType) pre2 - else singleType(pre2, sym1) - } else { - createDummyClone(pre) - } - case ThisType(clazz) => - if (clazz.isModuleClass) - maybeCreateDummyClone(clazz.typeOfThis, sym) - else if (sym.owner == clazz && (sym.hasFlag(PRIVATE) || sym.privateWithin == clazz)) - NoType - else - createDummyClone(pre) - case _ => - NoType - } - // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` - // generates an outer test based on `patType.prefix` with automatically dealises. - patType.dealias match { - case TypeRef(pre, sym, args) => - val pre1 = maybeCreateDummyClone(pre, sym) - (pre1 ne NoType) && isPopulated(copyTypeRef(patType, pre1, sym, args), selType) - case _ => - false - } - } - def normalizePlus(tp: Type): Type = { if (isRawType(tp)) rawToExistential(tp) else tp.normalize match { |