Mon, 02 Sep 2013 22:38:36 +0100
8016177: structural most specific and stuckness
Reviewed-by: jjg, vromero
Contributed-by: maurizio.cimadamore@oracle.com
mcimadamore@877 | 1 | /* |
jfranck@1689 | 2 | * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. |
mcimadamore@877 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
mcimadamore@877 | 4 | * |
mcimadamore@877 | 5 | * This code is free software; you can redistribute it and/or modify it |
mcimadamore@877 | 6 | * under the terms of the GNU General Public License version 2 only, as |
mcimadamore@877 | 7 | * published by the Free Software Foundation. |
mcimadamore@877 | 8 | * |
mcimadamore@877 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
mcimadamore@877 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
mcimadamore@877 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
mcimadamore@877 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
mcimadamore@877 | 13 | * accompanied this code). |
mcimadamore@877 | 14 | * |
mcimadamore@877 | 15 | * You should have received a copy of the GNU General Public License version |
mcimadamore@877 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
mcimadamore@877 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
mcimadamore@877 | 18 | * |
mcimadamore@877 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
mcimadamore@877 | 20 | * or visit www.oracle.com if you need additional information or have any |
mcimadamore@877 | 21 | * questions. |
mcimadamore@877 | 22 | */ |
mcimadamore@877 | 23 | |
mcimadamore@877 | 24 | /* |
mcimadamore@877 | 25 | * @test |
mcimadamore@982 | 26 | * @bug 7017664 7036906 |
mcimadamore@877 | 27 | * @summary Basher for CompoundScopes |
mcimadamore@877 | 28 | */ |
mcimadamore@877 | 29 | |
mcimadamore@877 | 30 | import java.util.Random; |
mcimadamore@877 | 31 | import java.util.Map; |
mcimadamore@877 | 32 | import java.util.HashMap; |
mcimadamore@877 | 33 | import com.sun.tools.javac.util.*; |
mcimadamore@877 | 34 | import com.sun.tools.javac.code.*; |
mcimadamore@877 | 35 | import com.sun.tools.javac.code.Scope.*; |
mcimadamore@877 | 36 | import com.sun.tools.javac.code.Symbol.*; |
mcimadamore@877 | 37 | import com.sun.tools.javac.file.JavacFileManager; |
mcimadamore@877 | 38 | |
mcimadamore@877 | 39 | public class CompoundScopeTest { |
mcimadamore@877 | 40 | public static void main(String... args) throws Exception { |
mcimadamore@877 | 41 | new CompoundScopeTest().run(args); |
mcimadamore@877 | 42 | } |
mcimadamore@877 | 43 | |
mcimadamore@877 | 44 | static final int MAX_SYMBOLS_COUNT = 20; |
mcimadamore@877 | 45 | static final int PASSES = 10; |
mcimadamore@877 | 46 | |
mcimadamore@877 | 47 | void run(String... args) throws Exception { |
mcimadamore@877 | 48 | int count = PASSES; |
mcimadamore@877 | 49 | |
mcimadamore@877 | 50 | for (int i = 0; i < args.length; i++) { |
mcimadamore@877 | 51 | String arg = args[i]; |
mcimadamore@877 | 52 | if (arg.equals("-seed") && (i + 1 < args.length)) |
mcimadamore@877 | 53 | seed = Long.parseLong(args[++i]); |
mcimadamore@877 | 54 | else if(arg.equals("-tests") && (i + 1 < args.length)) |
mcimadamore@877 | 55 | count = Integer.parseInt(args[++i]); |
mcimadamore@877 | 56 | else |
mcimadamore@877 | 57 | throw new Exception("unknown arg: " + arg); |
mcimadamore@877 | 58 | } |
mcimadamore@877 | 59 | |
mcimadamore@877 | 60 | rgen = new Random(seed); |
mcimadamore@877 | 61 | |
mcimadamore@877 | 62 | for (int i = 0; i < count; i++) { |
mcimadamore@877 | 63 | Test t = new Test(); |
mcimadamore@877 | 64 | t.run(); |
mcimadamore@877 | 65 | } |
mcimadamore@877 | 66 | |
mcimadamore@877 | 67 | if (errors > 0) |
mcimadamore@877 | 68 | throw new Exception(errors + " errors found"); |
mcimadamore@877 | 69 | } |
mcimadamore@877 | 70 | |
mcimadamore@877 | 71 | /** |
mcimadamore@877 | 72 | * Write a message to stderr. |
mcimadamore@877 | 73 | */ |
mcimadamore@877 | 74 | void log(String msg) { |
mcimadamore@877 | 75 | System.err.println(msg); |
mcimadamore@877 | 76 | } |
mcimadamore@877 | 77 | |
mcimadamore@877 | 78 | /** |
mcimadamore@877 | 79 | * Write an error message to stderr. |
mcimadamore@877 | 80 | */ |
mcimadamore@877 | 81 | void error(String msg) { |
mcimadamore@877 | 82 | System.err.println("Error: " + msg); |
mcimadamore@877 | 83 | errors++; |
mcimadamore@877 | 84 | } |
mcimadamore@877 | 85 | |
mcimadamore@877 | 86 | Random rgen; |
mcimadamore@877 | 87 | long seed = 0; |
mcimadamore@877 | 88 | |
mcimadamore@877 | 89 | int errors; |
mcimadamore@877 | 90 | |
mcimadamore@877 | 91 | /** Class to encapsulate a test run. */ |
mcimadamore@877 | 92 | class Test { |
mcimadamore@877 | 93 | |
mcimadamore@877 | 94 | List<Symbol> elems = List.nil(); |
mcimadamore@877 | 95 | Map<Name, List<Symbol>> shadowedMap = new HashMap<Name, List<Symbol>>(); |
mcimadamore@877 | 96 | |
mcimadamore@877 | 97 | /** Run the test. */ |
mcimadamore@877 | 98 | void run() throws Exception { |
mcimadamore@877 | 99 | log ("starting test"); |
mcimadamore@877 | 100 | setup(); |
mcimadamore@877 | 101 | Scope[] scopes = { createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)), |
mcimadamore@877 | 102 | createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)), |
mcimadamore@877 | 103 | createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)) }; |
mcimadamore@877 | 104 | boolean[][] scopeNesting = { {false, true, false, true}, |
mcimadamore@877 | 105 | {false, true, true, true}, |
mcimadamore@877 | 106 | {false, false, true, true} }; |
mcimadamore@877 | 107 | /** |
mcimadamore@877 | 108 | * We want to generate (and check) the following compound scopes: |
mcimadamore@877 | 109 | * C1 = C(S1, S2, S3) |
mcimadamore@877 | 110 | * C2 = C((S1, S2), S3) |
mcimadamore@877 | 111 | * C3 = C(S1, (S2, S3)) |
mcimadamore@877 | 112 | * C3 = C(C(S1, S2, S3)) |
mcimadamore@877 | 113 | */ |
mcimadamore@877 | 114 | for (int i = 0 ; i < 4 ; i ++) { |
mcimadamore@877 | 115 | CompoundScope root = new CompoundScope(symtab.noSymbol); |
mcimadamore@877 | 116 | CompoundScope sub = new CompoundScope(symtab.noSymbol); |
mcimadamore@877 | 117 | boolean subAdded = false; |
mcimadamore@877 | 118 | for (int sc = 0 ; sc < 3 ; sc ++) { |
mcimadamore@877 | 119 | if (scopeNesting[sc][i]) { |
mcimadamore@877 | 120 | sub.addSubScope(scopes[sc]); |
mcimadamore@877 | 121 | if (!subAdded) { |
mcimadamore@877 | 122 | root.addSubScope(sub); |
mcimadamore@877 | 123 | subAdded = true; |
mcimadamore@877 | 124 | } |
mcimadamore@877 | 125 | } else { |
mcimadamore@877 | 126 | root.addSubScope(scopes[sc]); |
mcimadamore@877 | 127 | } |
mcimadamore@877 | 128 | } |
mcimadamore@877 | 129 | log("testing scope: " + root); |
mcimadamore@982 | 130 | checkElems(root, null); |
mcimadamore@982 | 131 | checkElems(root, new OddFilter()); |
mcimadamore@982 | 132 | checkShadowed(root, null); |
mcimadamore@982 | 133 | checkShadowed(root, new OddFilter()); |
mcimadamore@982 | 134 | } |
mcimadamore@982 | 135 | } |
mcimadamore@982 | 136 | |
mcimadamore@982 | 137 | class OddFilter implements Filter<Symbol> { |
mcimadamore@982 | 138 | public boolean accepts(Symbol s) { |
mcimadamore@982 | 139 | Name numPart = s.name.subName(1, s.name.length()); |
mcimadamore@982 | 140 | return Integer.parseInt(numPart.toString()) % 2 != 0; |
mcimadamore@877 | 141 | } |
mcimadamore@877 | 142 | } |
mcimadamore@877 | 143 | |
mcimadamore@877 | 144 | /** |
mcimadamore@877 | 145 | * Create a scope containing a given number of synthetic symbols |
mcimadamore@877 | 146 | */ |
mcimadamore@877 | 147 | Scope createScope(int nelems) { |
mcimadamore@877 | 148 | Scope s = new Scope(symtab.noSymbol); |
mcimadamore@877 | 149 | for (int i = 0 ; i < nelems ; i++) { |
jfranck@1689 | 150 | Symbol sym = new TypeVariableSymbol(0, names.fromString("s" + i), null, null); |
mcimadamore@877 | 151 | s.enter(sym); |
mcimadamore@877 | 152 | elems = elems.prepend(sym); |
mcimadamore@877 | 153 | List<Symbol> shadowed = shadowedMap.get(sym.name); |
mcimadamore@877 | 154 | if (shadowed == null) { |
mcimadamore@877 | 155 | shadowed = List.nil(); |
mcimadamore@877 | 156 | } |
mcimadamore@877 | 157 | shadowedMap.put(sym.name, shadowed.prepend(sym)); |
mcimadamore@877 | 158 | } |
mcimadamore@877 | 159 | return s; |
mcimadamore@877 | 160 | } |
mcimadamore@877 | 161 | |
mcimadamore@877 | 162 | /** |
mcimadamore@877 | 163 | * Setup compiler context |
mcimadamore@877 | 164 | */ |
mcimadamore@877 | 165 | void setup() { |
mcimadamore@877 | 166 | log ("setup"); |
mcimadamore@877 | 167 | context = new Context(); |
mcimadamore@877 | 168 | JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab |
mcimadamore@877 | 169 | names = Names.instance(context); // Name.Table impls tied to an instance of Names |
mcimadamore@877 | 170 | symtab = Symtab.instance(context); |
mcimadamore@877 | 171 | } |
mcimadamore@877 | 172 | |
mcimadamore@877 | 173 | /** |
mcimadamore@877 | 174 | * Check that CompoundScope.getElements() correctly visits all symbols |
mcimadamore@877 | 175 | * in all subscopes (in the correct order) |
mcimadamore@877 | 176 | */ |
mcimadamore@982 | 177 | void checkElems(CompoundScope cs, Filter<Symbol> sf) { |
mcimadamore@877 | 178 | int count = 0; |
mcimadamore@982 | 179 | ListBuffer<Symbol> found = ListBuffer.lb(); |
mcimadamore@982 | 180 | List<Symbol> allSymbols = sf == null ? |
mcimadamore@982 | 181 | elems : |
mcimadamore@982 | 182 | filter(elems, sf); |
mcimadamore@982 | 183 | int expectedCount = allSymbols.length(); |
mcimadamore@982 | 184 | for (Symbol s : sf == null ? cs.getElements() : cs.getElements(sf)) { |
mcimadamore@877 | 185 | checkSameSymbols(s, allSymbols.head); |
mcimadamore@877 | 186 | allSymbols = allSymbols.tail; |
mcimadamore@982 | 187 | found.append(s); |
mcimadamore@877 | 188 | count++; |
mcimadamore@877 | 189 | } |
mcimadamore@982 | 190 | if (count != expectedCount) { |
mcimadamore@877 | 191 | error("CompoundScope.getElements() did not returned enough symbols"); |
mcimadamore@877 | 192 | } |
mcimadamore@877 | 193 | } |
mcimadamore@877 | 194 | |
mcimadamore@877 | 195 | /** |
mcimadamore@877 | 196 | * Check that CompoundScope.getElements() correctly visits all symbols |
mcimadamore@877 | 197 | * with a given name in all subscopes (in the correct order) |
mcimadamore@877 | 198 | */ |
mcimadamore@982 | 199 | void checkShadowed(CompoundScope cs, Filter<Symbol> sf) { |
mcimadamore@877 | 200 | for (Map.Entry<Name, List<Symbol>> shadowedEntry : shadowedMap.entrySet()) { |
mcimadamore@877 | 201 | int count = 0; |
mcimadamore@982 | 202 | List<Symbol> shadowed = sf == null ? |
mcimadamore@982 | 203 | shadowedEntry.getValue() : |
mcimadamore@982 | 204 | filter(shadowedEntry.getValue(), sf); |
mcimadamore@982 | 205 | int expectedCount = shadowed.length(); |
mcimadamore@877 | 206 | Name name = shadowedEntry.getKey(); |
mcimadamore@982 | 207 | for (Symbol s : sf == null ? cs.getElementsByName(name) : cs.getElementsByName(name, sf)) { |
mcimadamore@877 | 208 | checkSameSymbols(s, shadowed.head); |
mcimadamore@877 | 209 | shadowed = shadowed.tail; |
mcimadamore@877 | 210 | count++; |
mcimadamore@877 | 211 | } |
mcimadamore@982 | 212 | if (count != expectedCount) { |
mcimadamore@877 | 213 | error("CompoundScope.lookup() did not returned enough symbols for name " + name); |
mcimadamore@877 | 214 | } |
mcimadamore@877 | 215 | } |
mcimadamore@877 | 216 | } |
mcimadamore@877 | 217 | |
mcimadamore@982 | 218 | List<Symbol> filter(List<Symbol> elems, Filter<Symbol> sf) { |
mcimadamore@982 | 219 | ListBuffer<Symbol> res = ListBuffer.lb(); |
mcimadamore@982 | 220 | for (Symbol s : elems) { |
mcimadamore@982 | 221 | if (sf.accepts(s)) { |
mcimadamore@982 | 222 | res.append(s); |
mcimadamore@982 | 223 | } |
mcimadamore@982 | 224 | } |
mcimadamore@982 | 225 | return res.toList(); |
mcimadamore@982 | 226 | } |
mcimadamore@982 | 227 | |
mcimadamore@877 | 228 | void checkSameSymbols(Symbol found, Symbol req) { |
mcimadamore@877 | 229 | if (found != req) { |
mcimadamore@877 | 230 | error("Symbol mismatch - found : " + found + ":" + found.hashCode() + "\n" + |
mcimadamore@877 | 231 | " required : " + req + ":" + req.hashCode()); |
mcimadamore@877 | 232 | } |
mcimadamore@877 | 233 | } |
mcimadamore@877 | 234 | |
mcimadamore@877 | 235 | Context context; |
mcimadamore@877 | 236 | Symtab symtab; |
mcimadamore@877 | 237 | Names names; |
mcimadamore@877 | 238 | } |
mcimadamore@877 | 239 | } |