duke@1: /* ohair@554: * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as duke@1: * published by the Free Software Foundation. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: /* duke@1: * @test duke@1: * @bug 4607420 duke@1: * @summary A bug in the original JSR14 generics specification duke@1: * created a loophole in the type system. duke@1: * darcy@289: * @compile/fail Nonlinear.java duke@1: */ duke@1: duke@1: duke@1: public class Nonlinear { duke@1: duke@1: // This is an example of lack of type safety for duke@1: // the version of javac from jsr14_adding_generics-1_0-ea duke@1: duke@1: // It is a variant of the "classic" problem with polymorphic duke@1: // references in SML, which resulted in the usual array of duke@1: // fixes: notably value polymorphism. duke@1: duke@1: // This code compiles, but produces a ClassCastException duke@1: // when executed, even though there are no explicit casts in duke@1: // the program. duke@1: duke@1: public static void main (String [] args) { duke@1: Integer x = new Integer (5); duke@1: String y = castit (x); duke@1: System.out.println (y); duke@1: } duke@1: duke@1: static A castit (B x) { duke@1: // This method casts any type to any other type. duke@1: // Oh dear. This shouldn't type check, but does duke@1: // because build () returns a type Ref<*> duke@1: // which is a subtype of RWRef. duke@1: final RWRef r = build (); duke@1: r.set (x); duke@1: return r.get (); duke@1: } duke@1: duke@1: static Ref build () { duke@1: return new Ref (); duke@1: } duke@1: duke@1: // Another way of doing this is a variant of the crackit duke@1: // example discussed in the draft specification. duke@1: // duke@1: // The original duplicate was: duke@1: // duke@1: // static Pair duplicate (A x) { duke@1: // return new Pair (x,x); duke@1: // } duke@1: // duke@1: // which breaks the requirement that a type variable duke@1: // instantiated by * only occurs once in the result type. duke@1: // duke@1: // However, we can achieve the same result with a different duke@1: // type for duplicate, which uses its type variables linearly duke@1: // in the result: duke@1: duke@1: static > Pair,B> duplicate (B x) { duke@1: return new Pair,B> (x,x); duke@1: } duke@1: duke@1: // the cheat here is that A and B are used linearly in the result duke@1: // type, but not in the polymorphic bounds. duke@1: duke@1: // We can use that to give an alternative implementation of duke@1: // castit. duke@1: duke@1: static A castit2 (B x) { duke@1: Pair , Ref> p = duplicate (build ()); duke@1: p.snd.set (x); duke@1: return p.fst.get (); duke@1: } duke@1: duke@1: duke@1: } duke@1: duke@1: interface RWRef { duke@1: duke@1: public A get (); duke@1: public void set (B x); duke@1: duke@1: } duke@1: duke@1: class Ref implements RWRef { duke@1: duke@1: A contents; duke@1: duke@1: public void set (A x) { contents = x; } duke@1: public A get () { return contents; } duke@1: duke@1: } duke@1: duke@1: class Pair { duke@1: duke@1: final A fst; duke@1: final B snd; duke@1: duke@1: Pair (A fst, B snd) { this.fst = fst; this.snd = snd; } duke@1: duke@1: }