diff options
Diffstat (limited to 'sources/scalac/typechecker/Infer.java')
-rw-r--r-- | sources/scalac/typechecker/Infer.java | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java new file mode 100644 index 0000000000..b9f2071cc0 --- /dev/null +++ b/sources/scalac/typechecker/Infer.java @@ -0,0 +1,814 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** +** $Id$ +\* */ + +package scalac.typechecker; + +import scalac.Global; +import scalac.ApplicationError; +import scalac.*; +import scalac.util.*; +import scalac.ast.*; +import scalac.symtab.*; + +public class Infer implements Modifiers, Kinds { + + Global global; + Definitions definitions; + TreeGen gen; + TreeFactory make; + Substituter substituter; + + public Infer(Transformer trans) { + this.global = trans.global; + this.definitions = global.definitions; + this.gen = trans.gen; + this.make = trans.make; + this.substituter = new Substituter(global, trans.descr, gen); + } + +// Error messages ------------------------------------------------------------- + + String applyErrorMsg(String msg1, Tree fn, + String msg2, Type[] argtypes, Type pt) { + return msg1 + toString(fn.symbol(), fn.type) + msg2 + + ArrayApply.toString(argtypes, "(", ",", ")") + + (pt == Type.AnyType ? "" : " with expected result type " + pt); + } + + String typeErrorMsg(String msg, Type found, Type req) { + return msg + + ";\n found : " + found.toLongString() + + "\n required: " + req; + } + + String overloadResolveErrorMsg(Symbol sym1, Type tpe1, Symbol sym2, Type tpe2) { + return "ambiguous reference to overloaded definition,\n" + + "both " + sym1 + ": " + tpe1 + "\n" + + "and " + sym2 + ": " + tpe2 + " match."; + } + + /** Give a string representation of symbol `sym' with type `tp' + * for error diagnostics. `sym' may be null. + */ + static String toString(Symbol sym, Type tp) { + return + (tp instanceof Type.OverloadedType ? "overloaded " : "") + + (sym == null ? "expression" : sym) + " of type " + tp; + } + +// Helper definitions --------------------------------------------------------- + + /** Is type `tp' a polymorphic method type? + */ + private boolean isPolymorphic(Type tp) { + return tp.typeParams().length > 0; + } + + /** Is type `tp' a parameterized method type? + */ + /** Is type `tp' a parameterized method type? + */ + boolean isParameterized(Type tp) { + switch (tp) { + case MethodType(_, _): return true; + default: return isPolymorphic(tp); + } + } + +// Tree Substitution ------------------------------------------------------------- + + static class Substituter extends Transformer { + + Symbol[] tparams; + Type[] targs; + TreeGen gen; + + public Substituter(Global global, PhaseDescriptor descr, TreeGen gen) { + super(global, descr); + this.gen = gen; + } + + public Tree apply(Tree tree, Symbol[] tparams, Type[] targs) { + this.tparams = tparams; + this.targs = targs; + return transform(tree); + } + + public Tree transform(Tree tree) { +// System.out.println("[" + ArrayApply.toString(targs,"",",","") + "/" + ArrayApply.toString(tparams,"",",","") + "]" + tree + "@" + tree.symbol());//DEBUG + if (tree.type == null) return tree; + tree.type = tree.type.subst(tparams, targs); + switch (tree) { + case Ident(Name name): + if (name.isTypeName()) { + Symbol sym = tree.symbol(); + for (int i = 0; i < tparams.length; i++) { + if (tparams[i].name == sym.name && + tparams[i].owner() == sym.owner()) { + return gen.mkType(tree.pos, targs[i]); + } + } + } + return tree; + default: + return super.transform(tree); + } + } + } + +// Type parameter inference ----------------------------------------------------- + + private static class NoInstance extends RuntimeException { + NoInstance(String msg) { + super(msg); + } + } + + public static class VirtualPolyType extends Type.PolyType { + VirtualPolyType(Symbol[] tparams, Type result) { + super(tparams, result); + } + public String toString() { + return + ArrayApply.toString(Symbol.defString(tparams), "[ ", ",", " ]") + + result; + } + } + + /** map every TypeVar to its constraint.inst field. + * throw a NoInstance exception if a NoType or AnyType is encountered. + */ + private static Type.Map instantiateMap = new Type.Map() { + public Type apply(Type t) { + return instantiate(t); + } + }; + + private static Type instantiate(Type tp) throws NoInstance { + switch (tp) { + case AnyType: + case NoType: + throw new NoInstance("undetermined type"); + case TypeVar(Type origin, Type.Constraint constr): + if (constr.inst != Type.NoType) return instantiate(constr.inst); + else throw new NoInstance("no unique instantiation of type variable " + + origin + " could be found"); + default: + return instantiateMap.map(tp); + } + } + + /** Map type variable to its instance, or, if `covariant' is true, + * to its upper bound (if this is not AnyType); + * or return `AnyType' if not possible. + */ + private Type instantiateUpper(Type tp, boolean covariant) throws NoInstance { + switch (tp) { + case TypeVar(Type origin, Type.Constraint constr): + if (constr.inst != Type.NoType) { + return instantiate(constr.inst); + } else if (covariant && constr.hibounds != Type.List.EMPTY) { + maximizeVar(tp); + return instantiate(constr.inst); + } + return Type.AnyType; + default: + throw new ApplicationError(); + } + } + + /** Is type fully defined, i.e. no embedded anytypes or typevars in it? + */ + public boolean isFullyDefined(Type tp) { + try { + instantiate(tp); + return true; + } catch (NoInstance ex) { + return false; + } + } + + /** Do type arguments `targs' conform to formal parameters `tparams'? + */ + private boolean isWithinBounds(Symbol[] tparams, Type[] targs) { + // check that covariant types do not appear in F-bounds. + for (int i = 0; i < targs.length; i++) { + if (targs[i].isCovarType()) { + for (int j = 0; j < tparams.length; j++) + if (tparams[j].info().contains(tparams[i])) + return false; + } + } + for (int i = 0; i < targs.length; i++) { + if (!targs[i].dropVariance().isSubType( + tparams[i].info().subst(tparams, targs))) + return false; + } + return true; + } + + /** throw a type error if arguments not within bounds. + */ + void checkBounds(Symbol[] tparams, Type[] targs, String prefix) { + if (!isWithinBounds(tparams, targs)) { + throw new Type.Error( + prefix + "type arguments " + + ArrayApply.toString(targs, "[", ",", "]") + " do not conform to " + + tparams[0].owner() + "'s type parameter bounds " + + ArrayApply.toString(Symbol.defString(tparams), "[", ",", "]")); + } + } + + /** Instantiate undetermined variable to its minimal upper bound. + * Throw a NoInstance exception if this not possible. + */ + private void maximizeVar(Type tp) throws NoInstance { + switch (tp) { + case TypeVar(Type origin, Type.Constraint constr): + if (constr.inst == Type.NoType) { + if (constr.hibounds == Type.List.EMPTY) + constr.inst = definitions.ANY_TYPE; + else if (constr.hibounds.tail == Type.List.EMPTY) + constr.inst = constr.hibounds.head; + else { + for (Type.List bs = constr.hibounds; + bs != Type.List.EMPTY && constr.inst == Type.NoType; + bs = bs.tail) { + //System.out.println("hibound: " + bs.head);//DEBUG + if (isSubSymOfAll(bs.head, constr.hibounds)) { + //System.out.println("best: " + bs.head);//DEBUG + constr.inst = bs.head.any2typevar(); + } + } + } + if (constr.inst == Type.NoType || + !isSubTypeOfAll(constr.inst, constr.hibounds)) { + throw new NoInstance( + "no unique maximal instance exists for type variable " + + origin); + } + } + return; + default: + throw new ApplicationError(); + } + } + //where + private boolean isSubSymOfAll(Type tp, Type.List tps) { + Symbol sym = tp.unalias().symbol(); + for (Type.List l = tps; l != Type.List.EMPTY; l = l.tail) { + if (!isSubSym(sym, l.head.unalias().symbol())) return false; + } + return true; + } + + private boolean isSubSym(Symbol sym, Symbol sym1) { + return + sym == sym1 || + sym.kind == ERROR || + (sym.kind == TYPE || sym.kind == CLASS) && sym.isSubClass(sym1); + } + + private boolean isSubTypeOfAll(Type tp, Type.List tps) { + for (Type.List l = tps; l != Type.List.EMPTY; l = l.tail) { + if (!tp.isSubType(l.head)) return false; + } + return true; + } + + private void minimizeVar(Type tp) { + switch (tp) { + case TypeVar(Type origin, Type.Constraint constr): + if (constr.inst == Type.NoType && constr.lobounds != Type.List.EMPTY) + constr.inst = Type.lub(constr.lobounds.toArray()); + return; + default: + throw new ApplicationError(); + } + } + + private Type[] freshVars(Symbol[] tparams) { + Type[] tvars = new Type[tparams.length]; + for (int i = 0; i < tvars.length; i++) { + tvars[i] = Type.TypeVar(tparams[i].type(), new Type.Constraint()); + } + return tvars; + } + + private Type.Map freshInstanceMap = new Type.Map() { + public Type apply(Type t) { + switch (t) { + case PolyType(Symbol[] tparams, Type restp): + Symbol[] newparams = new Symbol[tparams.length]; + for (int i = 0; i < tparams.length; i++) + newparams[i] = tparams[i].cloneSymbol(); + for (int i = 0; i < tparams.length; i++) + newparams[i].setInfo( + newparams[i].info().subst(tparams, newparams)); + return Type.PolyType( + newparams, apply(restp).subst(tparams, newparams)); + case OverloadedType(_, _): + return map(t); + default: + return t; + } + } + }; + + public Type freshInstance(Type tp) { + return freshInstanceMap.apply(tp); + } + + /** Automatically perform the following conversions on expression types: + * A method type becomes the corresponding function type. + * A nullary method type becomes its result type. + */ + private Type normalize(Type tp, Type pt) { + switch (tp) { + case MethodType(Symbol[] params, Type restype): + return global.definitions.functionType( + Symbol.type(params), normalize(restype, Type.AnyType)); + case PolyType(Symbol[] tparams, Type restype): + if (tparams.length == 0) return normalize(restype, pt); + } + return tp; + } + + boolean isCompatible(Type tp, Type pt) { + return normalize(tp, pt).isSubType(pt); + } + + private Symbol[] normalizeArgs(Type[] targs, Symbol[] tparams) { + Type.List uninstantiated = Type.List.EMPTY; + for (int i = 0; i < targs.length; i++) { + if (targs[i] == Type.NoType) { + targs[i] = tparams[i].type(); + uninstantiated = Type.List.append(uninstantiated, targs[i]); + } + } + return Type.symbol(uninstantiated.toArray()); + } + + /** Return inferred type arguments of polymorphic expression, given + * its type parameters and result type and a prototype `pt'. + * If no maximal type variables exists that make the + * instantiated type a subtype of `pt' and `lastTry' is true, return `null'. + */ + private Type[] instTypeArgs(Symbol[] tparams, Type restype, Type pt) { + Type[] tvars = freshVars(tparams); + // add all bounds except F-bounds to upper bounds of type variable. + for (int i = 0; i < tvars.length; i++) { + switch (tvars[i]) { + case TypeVar(_, Type.Constraint constr): + Type bound = tparams[i].info(); + if (!bound.containsSome(tparams)) + constr.hibounds = new Type.List(bound, Type.List.EMPTY); + } + } + Type insttype = restype.subst(tparams, tvars); + if (isCompatible(insttype, pt)) { + try { + Type[] targs = new Type[tvars.length]; + for (int i = 0; i < tvars.length; i++) { + maximizeVar(tvars[i]); + targs[i] = instantiate(tvars[i]); + } + return targs; + } catch (NoInstance ex) { + } + } + return null; + } + + /** As before, but: don't maximize. Instead map all unistantiated + * type vars to AnyType. + */ + public Type[] protoTypeArgs(Symbol[] tparams, Type restype, Type pt, + Symbol[] params) { + Type[] tvars = freshVars(tparams); + Type insttype = restype.subst(tparams, tvars); + Type[] targs = new Type[tvars.length]; + if (isCompatible(insttype, pt)) { + for (int i = 0; i < tvars.length; i++) { + targs[i] = instantiateUpper(tvars[i], isCovariant(tparams[i], params)); + } + } else { + for (int i = 0; i < tvars.length; i++) { + targs[i] = Type.AnyType; + } + } + return targs; + } + + /** Does given `tparam' occur only covariantly in symbols? + */ + private boolean isCovariant(Symbol tparam, Symbol[] syms) { + for (int i = 0; i < syms.length; i++) { + if (!isCovariant(tparam, syms[i])) return false; + } + return true; + } + + /** Does given `tparam' occur only covariantly in symbol? + */ + private boolean isCovariant(Symbol tparam, Symbol sym) { + switch (sym.kind) { + case ERROR: case VAL: case TYPE: return isCovariant(tparam, sym.info()); + case ALIAS: return !sym.info().contains(tparam); + default: return false; + } + } + + /** Does given `tparam' occur only covariantly in types? + */ + private boolean isCovariant(Symbol tparam, Type[] tps) { + for (int i = 0; i < tps.length; i++) { + if (!isCovariant(tparam, tps[i])) return false; + } + return true; + } + + /** Does given `tparam' occur only covariantly in argument types? + */ + private boolean isCovariantArgs(Symbol tparam, Type[] tps) { + for (int i = 0; i < tps.length; i++) { + switch (tps[i]) { + case CovarType(Type t): + if (!isCovariant(tparam, t)) return false; + break; + default: + if (tps[i].contains(tparam)) return false; + } + } + return true; + } + + /** Does given `tparam' occur only covariantly in type? + */ + private boolean isCovariant(Symbol tparam, Type tp) { + switch (tp) { + case ErrorType: + case AnyType: + case NoType: + case ThisType(Symbol sym): + return true; + case TypeRef(Type pre, Symbol sym, Type[] args): + return isCovariant(tparam, pre) && isCovariantArgs(tparam, args); + case SingleType(Type pre, Symbol sym): + return !pre.contains(tparam); + case CompoundType(Type[] parts, Scope members): + return isCovariant(tparam, parts) && + isCovariant(tparam, members.elements()); + default: + throw new ApplicationError(); + } + } + + /** Return inferred type arguments, given type parameters, formal parameters and + * argument types. + * If this is not possible, throw a `NoInstance' exception, or, if + * `needToSucceed' is false alternatively return `null'. + * Undetermined type arguments are represented by `NoType'. + * No check that inferred parameters conform to their bounds is made here. + */ + private Type[] methTypeArgs(Symbol[] tparams, Symbol[] params, Type[] argtypes, + boolean needToSucceed) throws NoInstance { + //System.out.println("methTypeArgs, tparams = " + ArrayApply.toString(tparams) + ", params = " + ArrayApply.toString(params) + ", type(params) = " + ArrayApply.toString(Symbol.type(params)) + ", argtypes = " + ArrayApply.toString(argtypes));//DEBUG + + Type[] tvars = freshVars(tparams); + Type[] formals = Symbol.type(params); + if (formals.length != argtypes.length) { + if (needToSucceed) + throw new NoInstance("parameter lists differ in length"); + return null; + } + for (int i = 0; i < formals.length; i++) { + if (!isCompatible(argtypes[i].subst(tparams, tvars), + formals[i].subst(tparams, tvars))) { + if (needToSucceed) + throw new NoInstance( + typeErrorMsg( + "argument expression's type is not compatible with formal parameter type", + argtypes[i].subst(tparams, tvars), + formals[i].subst(tparams, tvars))); + return null; + } + } + Type[] targs = new Type[tvars.length]; + for (int i = 0; i < tvars.length; i++) { + minimizeVar(tvars[i]); + targs[i] = (((Type.TypeVar) tvars[i]).constr.inst == Type.NoType) + ? Type.NoType + : instantiate(tvars[i]); + } + return targs; + } + + /** Create and attribute type application node. Pass arguments for that + * `tparams' prefix which is owned by the tree's symbol. If there are remaining + * type parameters, substitute corresponding type arguments for them in the + * tree. Such remaining type parameters always come from an inferred PolyType. + */ + public Tree mkTypeApply(Tree tree, Symbol[] tparams, Type restype, Type[] targs) { + Tree tree1 = tree; + Symbol sym = tree.symbol(); + int i = 0; + while (i < tparams.length && tparams[i].owner() == sym) + i++; + if (i < tparams.length) { + //new Printer().print(tree1);//DEBUG + //System.out.println(ArrayApply.toString(targs) + "/" + i + "/" + ArrayApply.toString(tparams));//DEBUG + Symbol[] tparams1 = new Symbol[tparams.length - i]; + System.arraycopy(tparams, i, tparams1, 0, tparams1.length); + Type[] targs1 = new Type[tparams.length - i]; + System.arraycopy(targs, i, targs1, 0, targs1.length); + tree1 = substituter.apply(tree1, tparams1, targs1); + } + if (0 < i) { + Tree[] argtrees = new Tree[i]; + for (int j = 0; j < i; j++) + argtrees[j] = gen.mkType(tree.pos, targs[j]); + tree1 = make.TypeApply(tree.pos, tree1, argtrees); + } + //System.out.println(Sourcefile.files[Position.file(tree1.pos)] + ": "); + return tree1.setType(restype.subst(tparams, targs)); + } + + /** Return the instantiated and normalized type of polymorphic expression + * with type `[tparams]restype', given a two prototypes `pt1', and `pt2'. + * `pt1' is the strict first attempt prototype where type parameters + * are left unchanged. `pt2' is the fall-back prototype where type parameters + * are replaced by `AnyType's. We try to instantiate first to `pt1' and then, + * if this fails, to `pt2'. If both atempts fail, a `Type.Error' is thrown. + */ + Type argumentTypeInstance(Symbol[] tparams, Type restype, Type pt1, Type pt2) + throws Type.Error { + switch (restype) { + case PolyType(Symbol[] tparams1, Type restype1): + Symbol[] tparams2 = new Symbol[tparams.length + tparams1.length]; + System.arraycopy(tparams, 0, tparams2, 0, tparams.length); + System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length); + return argumentTypeInstance(tparams2, restype1, pt1, pt2); + default: + if (tparams.length != 0) { + Type[] targs = instTypeArgs(tparams, restype, pt1); + if (targs == null) + targs = instTypeArgs(tparams, restype, pt2); + if (targs == null) + throw new Type.Error( + typeErrorMsg( + "polymorphic argument cannot be instantiated to formal parameter type", + Type.PolyType(tparams, restype), pt2)); + checkBounds(tparams, targs, "inferred "); + return restype.subst(tparams, targs); + } else { + return normalize(restype, pt2); + } + } + } + + /** Instantiate expression `tree' of polymorphic type with given `tparams' and + * `restype', using prototype `pt'. + */ + public Tree exprInstance(Tree tree, Symbol[] tparams, Type restype, Type pt) + throws Type.Error { + switch (restype) { + case PolyType(Symbol[] tparams1, Type restype1): + Symbol[] tparams2 = new Symbol[tparams.length + tparams1.length]; + System.arraycopy(tparams, 0, tparams2, 0, tparams.length); + System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length); + return exprInstance(tree, tparams2, restype1, pt); + } + Type[] targs = instTypeArgs(tparams, restype, pt); + if (targs == null) + throw new Type.Error( + "polymorphic expression of type " + tree.type + + " cannot be instantiated from expected type " + pt); + checkBounds(tparams, targs, "inferred "); + return mkTypeApply(tree, tparams, restype, targs); + } + + /** Instantiate method `tree' of polymorphic type with given `tparams' and + * `restype', so that resulting method type can be applied to + * arguments with types `argtypes'. + */ + public Tree methodInstance(Tree tree, + Symbol[] tparams, Type restype, Type[] argtypes) + throws Type.Error { + switch (restype) { + case PolyType(Symbol[] tparams1, Type restype1): + Symbol[] tparams2 = new Symbol[tparams.length + tparams1.length]; + System.arraycopy(tparams, 0, tparams2, 0, tparams.length); + System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length); + return methodInstance(tree, tparams2, restype1, argtypes); + case MethodType(Symbol[] params, Type restpe): + Type[] argtypes1 = Type.widen(argtypes); + Type[] targs; + try { + targs = methTypeArgs(tparams, params, argtypes1, true); + } catch (NoInstance ex) { + throw new Type.Error( + applyErrorMsg( + "no type parameters for ", tree, + " exist so that it can be applied to arguments ", + argtypes1, Type.AnyType) + + "\n --- because ---\n" + ex.getMessage()); + } + Symbol[] uninstantiated = normalizeArgs(targs, tparams); + checkBounds(tparams, targs, "inferred "); + Type restype1 = (uninstantiated.length == 0) ? restype + : Type.MethodType(params, + new VirtualPolyType(uninstantiated, restpe)); + return mkTypeApply(tree, tparams, restype1, targs); + default: + return tree; + } + } + + /** Instantiate constructor `tree' of polymorphic type with given `tparams' and + * `restype', so that its result type matches prototype `pt'. + */ + public void constructorInstance(Tree tree, + Symbol[] tparams, Type restype, Type pt) + throws Type.Error { + switch (restype) { + case PolyType(Symbol[] tparams1, Type restype1): + Symbol[] tparams2 = new Symbol[tparams.length + tparams1.length]; + System.arraycopy(tparams, 0, tparams2, 0, tparams.length); + System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length); + constructorInstance(tree, tparams2, restype1, pt); + return; + } + Type[] tvars = freshVars(tparams); + Type restype1 = restype.subst(tparams, tvars); + Type ctpe1 = restype1.resultType(); + if (ctpe1.isSubType(pt)) { + Type[] targs = new Type[tparams.length]; + for (int i = 0; i < tvars.length; i++) { + try { + targs[i] = instantiateUpper(tvars[i], true); + } catch (NoInstance ex) { + throw new Type.Error( + "constructor of type " + ctpe1 + + " can be instantiated in mode than one way to expected type " + + pt + + "\n --- because ---\n" + ex.getMessage()); + } + } + checkBounds(tparams, targs, "inferred "); + tree.setType(restype.subst(tparams, targs)); + //System.out.println("inferred constructor type: " + tree.type);//DEBUG + } else { + throw new Type.Error( + typeErrorMsg( + "constructor cannot be instantiated to expected type", + ctpe1, pt)); + } + } + +// Overload Resolution ------------------------------------------------------------- + + /** Is function type `ftpe' applicable to `argtypes' and + * does its result conform to `pt'? + */ + boolean isApplicable(Type ftpe, Type[] argtypes, Type pt) { + switch (ftpe) { + case MethodType(Symbol[] params, Type restpe): + return + isCompatible(restpe, pt) && + params.length == argtypes.length && + Type.isSubType(argtypes, Symbol.type(params)); + case PolyType(Symbol[] tparams, MethodType(Symbol[] params, Type restpe)): + try { + Type[] targs = methTypeArgs( + tparams, params, Type.widen(argtypes), false); + if (targs != null) { + Symbol[] uninstantiated = normalizeArgs(targs, tparams); + return + isWithinBounds(tparams, targs) && + instTypeArgs(uninstantiated, restpe.subst(tparams, targs), pt) + != null; + } + } catch (NoInstance ex) { + } + } + return false; + } + + /** Does function type `ftpe1' specialize function type `ftpe2' + * when both are alternatives in an overloaded function? + */ + boolean specializes(Type ftpe1, Type ftpe2) { + switch (ftpe1) { + case MethodType(Symbol[] params, _): + return isApplicable(ftpe2, Symbol.type(params), Type.AnyType); + case PolyType(_, MethodType(Symbol[] params, _)): + return isApplicable(ftpe2, Symbol.type(params), Type.AnyType); + default: + return false; + } + } + + /** Assign `tree' the type of the alternative which matches + * prototype `pt', if it exists. + * If several alternatives match `pt', take unique parameterless one. + * Throw a Type.Error if several such alternatives exist. + * If no alternative matches, leave `tree' unchanged. + */ + public void exprAlternative(Tree tree, Symbol[] alts, + Type[] alttypes, Type pt) + throws Type.Error { + if (alts.length == 1) { + tree.setSymbol(alts[0]).setType(alttypes[0]); + return; + } + int best = -1; + for (int i = 0; i < alttypes.length; i++) { + if (isCompatible(alttypes[i], pt) && + (best < 0 || improves(alttypes[i], alttypes[best]))) { + best = i; + } + } + if (best >= 0) { + for (int i = 0; i < alttypes.length; i++) { + if (isCompatible(alttypes[i], pt) && + best != i && !improves(alttypes[best], alttypes[i])) { + throw new Type.Error(overloadResolveErrorMsg( + alts[best], alttypes[best], alts[i], alttypes[i])); + } + } + tree.setSymbol(alts[best]).setType(alttypes[best]); + } + } + //where + private boolean improves(Type tp1, Type tp2) { + return !isParameterized(tp1) && isParameterized(tp2); + } + + /** Assign `tree' the type of an alternative + * which is applicable to `argtypes', and whose result type is + * a subtype of `pt' if it exists. + * If several applicable alternatives exist, take the + * most specialized one, or throw an error if no + * most specialized applicable alternative exists. + * If no alternative matches, leave `tree' unchanged. + */ + public void methodAlternative(Tree tree, Symbol[] alts, Type[] alttypes, + Type[] argtypes, Type pt) + throws Type.Error { + if (alts.length == 1) { + tree.setSymbol(alts[0]).setType(alttypes[0]); + return; + } + int best = -1; + for (int i = 0; i < alttypes.length; i++) { + if (isApplicable(alttypes[i], argtypes, pt) && + (best < 0 || specializes(alttypes[i], alttypes[best]))) best = i; + } + if (best >= 0) { + for (int i = 0; i < alttypes.length; i++) { + if (i != best && + isApplicable(alttypes[i], argtypes, pt) && + !(specializes(alttypes[best], alttypes[i]) && + !specializes(alttypes[i], alttypes[best]))) { + throw new Type.Error(overloadResolveErrorMsg( + alts[best], alttypes[best], alts[i], alttypes[i])); + } + } + tree.setSymbol(alts[best]).setType(alttypes[best]); + } + } + + /** Assign `tree' the type of unique polymorphic alternative with `nparams' numbers + * of type parameters, if it exists. + * throw error if several polymorphic alternatives exist. + * If no alternative matches, leave `tree' unchanged. + */ + public void polyAlternative(Tree tree, + Symbol[] alts, Type[] alttypes, int nparams) + throws Type.Error { + if (alts.length == 1) { + tree.setSymbol(alts[0]).setType(alttypes[0]); + return; + } + int i = 0; + while (i < alttypes.length && + !(alts[i].isValue() && alttypes[i].typeParams().length == nparams)) { + i++; + } + if (i < alttypes.length) { + for (int j = i + 1; j < alttypes.length; j++) { + if (alts[i].isValue() && alttypes[i].typeParams().length == nparams) + throw new Type.Error(overloadResolveErrorMsg( + alts[i], alttypes[i], alts[j], alttypes[j])); + } + tree.setSymbol(alts[i]).setType(alttypes[i]); + } + } +} + |