diff options
author | paltherr <paltherr@epfl.ch> | 2004-02-19 13:08:48 +0000 |
---|---|---|
committer | paltherr <paltherr@epfl.ch> | 2004-02-19 13:08:48 +0000 |
commit | d19cd4e6791347cfbcd161c02a49eebef4aab686 (patch) | |
tree | c8cc3229b42c7656e9148765b0fac3f22e21252b /sources/scalac/typechecker/Infer.java | |
parent | 3b4e70e1bdf4dcf237d398157b13cbd941e1001e (diff) | |
download | scala-d19cd4e6791347cfbcd161c02a49eebef4aab686.tar.gz scala-d19cd4e6791347cfbcd161c02a49eebef4aab686.tar.bz2 scala-d19cd4e6791347cfbcd161c02a49eebef4aab686.zip |
- Removed java version of files translated to s...
- Removed java version of files translated to scala
Diffstat (limited to 'sources/scalac/typechecker/Infer.java')
-rw-r--r-- | sources/scalac/typechecker/Infer.java | 1059 |
1 files changed, 4 insertions, 1055 deletions
diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java index e5ca7f6d0d..8ccca5d586 100644 --- a/sources/scalac/typechecker/Infer.java +++ b/sources/scalac/typechecker/Infer.java @@ -8,1064 +8,13 @@ package scalac.typechecker; -import scalac.Global; -import scalac.ApplicationError; -import scalac.*; -import scalac.util.*; -import scalac.ast.*; -import scalac.symtab.*; +import scalac.symtab.Symbol; +import scalac.symtab.Type; -public class Infer implements Modifiers, Kinds { - - Global global; - Definitions definitions; - TreeGen gen; - TreeFactory make; - Substituter substituter; - - public Infer(Global global, TreeGen gen, TreeFactory make) { - this.global = global; - this.definitions = global.definitions; - this.gen = gen; - this.make = make; - this.substituter = new Substituter(global, gen); - } - - public Infer(Transformer trans) { - this(trans.global, trans.gen, trans.make); - } - -// Error messages ------------------------------------------------------------- - - public 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); - } - - public String typeErrorMsg(String msg, Type found, Type req) { - return msg + - ";\n found : " + found.toLongString() + - "\n required: " + req; - } - - public String overloadResolveErrorMsg(Symbol sym1, Type tpe1, Symbol sym2, Type tpe2) { - return "ambiguous reference to overloaded definition,\n" + - "both " + sym1 + ": " + tpe1 + "\n" + - "and " + sym2 + ": " + tpe2 + "\nmatch"; - } - - /** Give a string representation of symbol `sym' with type `tp' - * for error diagnostics. `sym' may be null. - */ - public String toString(Symbol sym, Type tp) { - return - (tp instanceof Type.OverloadedType ? "overloaded " : "") + - (sym == null ? "expression" : sym) + " of type " + tp; - } - -// Tree Substitution ------------------------------------------------------------- - - static class Substituter extends Transformer { - - Symbol[] tparams; - Type[] targs; - TreeGen gen; - Type.SubstTypeMap typeSubstituter; - - public Substituter(Global global, TreeGen gen) { - super(global); - this.gen = gen; - } - - public Tree apply(Tree tree, Symbol[] tparams, Type[] targs) { - this.tparams = tparams; - this.targs = targs; - this.typeSubstituter = new Type.SubstTypeMap(tparams, targs) { - public boolean matches(Symbol sym1, Symbol sym2) { - return - sym1.name == sym2.name && sym1.owner() == sym2.owner(); - } - }; - return transform(tree); - } - - Type.Map elimInferredPolyMap = new Type.Map() { - public Type apply(Type t) { - switch (t) { - case PolyType(Symbol[] tparams1, Type restp): - if (tparams1.length == tparams.length && - tparams1[0] == tparams[0]) { - for (int i = 1; i < tparams.length; i++) - assert tparams1[i] == tparams[i]; - return apply(restp); - } - } - return map(t); - } - }; - - public Tree transform(Tree tree) { -// System.out.println("[" + ArrayApply.toString(targs,"",",","") + "/" + ArrayApply.toString(tparams,"",",","") + "]" + tree + "@" + tree.symbol());//DEBUG - if (tree.type != null) { - tree.type = typeSubstituter.apply( - elimInferredPolyMap.apply(tree.type)); - } - switch (tree) { - case Ident(Name name): - if (name.isTypeName()) { - Symbol sym = tree.symbol(); - for (int i = 0; i < tparams.length; i++) { - if (typeSubstituter.matches(tparams[i], sym)) { - return gen.mkType(tree.pos, targs[i]); - } - } - } - return tree; - - case TypeApply(Tree fun, Tree[] targs): - boolean proceed = true; - switch (fun.type) { - case PolyType(Symbol[] tparams1, _): - if (tparams1.length == tparams.length && - tparams1[0] == tparams[0] && - targs.length == tparams.length) { - proceed = false; - for (int i = 0; i < tparams.length; i++) - if (!typeSubstituter.matches(targs[i].type.symbol(), tparams[i])) - proceed = true; - } - } - Tree fun1 = proceed ? transform(fun) : fun; - Tree[] targs1 = transform(targs); - return copy.TypeApply(tree, fun1, targs1); - -/* - case TypeTerm(): - Symbol sym = tree.type.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); - } - } - } - -// Variance calculation ---------------------------------------------------------- - - private static int flip(int v) { - if (v == COVARIANT) return CONTRAVARIANT; - else if (v == CONTRAVARIANT) return COVARIANT; - else return v; - } - - private static static int cut(int v) { - if (v == VARIANCES) return v; - else return 0; - } - - /** Compute variances of all type parameters `tparams' in type `tp'. - * A variance is taken from the four point lattice - * - * 0, Modifiers.COVARIANT, Modifiers.CONTRAVARIANT, Modifiers.VARIANCES. - */ - private static int[] variance(Symbol[] tparams, Type tp) { - int[] vs = new int[tparams.length]; - for (int i = 0; i < vs.length; i++) vs[i] = variance(tparams[i], tp); - return vs; - } - - /** Compute variances of all type parameters `tparams' in types `tps'. - */ - private static int[] variance(Symbol[] tparams, Type[] tps) { - int[] vs = new int[tparams.length]; - for (int i = 0; i < vs.length; i++) vs[i] = variance(tparams[i], tps); - return vs; - } - - /** Compute variance of type parameter `tparam' in types of all symbols `sym'. - */ - private static int variance(Symbol tparam, Symbol[] syms) { - int v = VARIANCES; - for (int i = 0; i < syms.length; i++) { - v = v & variance(tparam, syms[i]); - } - return v; - } - - /** Compute variance of type parameter `tparam' in type of symbol `sym'. - */ - private static int variance(Symbol tparam, Symbol sym) { - switch (sym.kind) { - case ERROR: - return VARIANCES; - case VAL: - return variance(tparam, sym.info()); - case TYPE: - return variance(tparam, sym.info()) & - flip(variance(tparam, sym.loBound())); - case ALIAS: - return cut(variance(tparam, sym.info())); - default: - return 0; - } - } - - /** Compute variance of type parameter `tparam' in all types `tps'. - */ - private static int variance(Symbol tparam, Type[] tps) { - int v = VARIANCES; - for (int i = 0; i < tps.length; i++) { - v = v & variance(tparam, tps[i]); - } - return v; - } - - /** Compute variance of type parameter `tparam' in all type arguments - * `tps' which correspond to formal type parameters `tparams'. - */ - private static int varianceInArgs(Symbol tvar, Type[] tps, Symbol[] tparams) { - int v = VARIANCES; - for (int i = 0; i < tps.length; i++) { - if ((tparams[i].flags & COVARIANT) != 0) { - v = v & variance(tvar, tps[i]); - } else if ((tparams[i].flags & CONTRAVARIANT) != 0) { - v = v & flip(variance(tvar, tps[i])); - } else { - v = v & cut(variance(tvar, tps[i])); - } - } - return v; - } - - /** Does given `tparam' occur with variance `v' in type? - */ - private static int variance(Symbol tparam, Type tp) { - switch (tp) { - case ErrorType: - case AnyType: - case NoType: - case ThisType(_): - case ConstantType(_, _): - return VARIANCES; - case TypeRef(Type pre, Symbol sym, Type[] args): - if (sym == tparam) return COVARIANT; - else return variance(tparam, pre) & - varianceInArgs(tparam, args, sym.typeParams()); - case SingleType(Type pre, Symbol sym): - return cut(variance(tparam, pre)); - case CompoundType(Type[] parts, Scope members): - return variance(tparam, parts) & variance(tparam, members.elements()); - case MethodType(Symbol[] params, Type restype): - return flip(variance(tparam, params)) & variance(tparam, restype); - case PolyType(Symbol[] tparams, Type restype): - return flip(variance(tparam, tparams)) & variance(tparam, restype); - default: - throw new ApplicationError(tp.toString()); - } - } - -// Type parameter inference ----------------------------------------------------- - - private static class NoInstance extends RuntimeException { - NoInstance(String msg) { - super(msg); - } - } - - /** 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; - */ - private Type instantiateToBound(Type tp, int variance) { - switch (tp) { - case TypeVar(Type origin, Type.Constraint constr): - try { - if (constr.inst != Type.NoType) { - return instantiate(constr.inst); - } else if ((variance & COVARIANT) != 0 && - constr.hibounds != Type.List.EMPTY) { - maximizeVar(tp); - return instantiate(constr.inst); - } else if ((variance & CONTRAVARIANT) != 0 && - constr.lobounds != Type.List.EMPTY) { - minimizeVar(tp); - return instantiate(constr.inst); - } - } catch (NoInstance ex) { - } - return Type.AnyType; - default: - throw new ApplicationError(); - } - } - - /** The formal parameter types corresponding to `params'. - * If `params' is a repeated parameter, a list of `length' copies - * of its type is returned. - */ - public Type[] formalTypes(Symbol[] params, int nargs) { - Type[] result; - if (params.length > 0 && - (params[params.length-1].flags & REPEATED) != 0) { - Type[] args = params[params.length-1].type().typeArgs(); - if (args.length == 1) { - Type ft = args[0]; - // last param has type Seq[T], we need T here - Type[] formals = new Type[nargs]; - int i = 0; - while (i < params.length-1) { - formals[i] = params[i].type(); - i++; - } - while (i < nargs) { - formals[i] = ft; - i++; - } - return formals; - } - } - return Symbol.type(params); - } - - /** 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) { - for (int i = 0; i < targs.length; i++) { - Type hibound = tparams[i].info().subst(tparams, targs); - if (!targs[i].isSubType(hibound)) { - for (int j = 0; j < tparams.length; j++) { - if (hibound.symbol() == tparams[j]) - return isWithinBounds( - tparams, - Type.subst( - targs, - new Symbol[]{tparams[j]}, - new Type[]{targs[i]})); - } - return false; - } - Type lobound = tparams[i].loBound().subst(tparams, targs); - if (!lobound.isSubType(targs[i])) { - for (int j = 0; j < tparams.length; j++) { - if (lobound.symbol() == tparams[j]) - return isWithinBounds( - tparams, - Type.subst( - targs, - new Symbol[]{tparams[j]}, - new Type[]{targs[i]})); - } - return false; - } - } - return true; - } +public abstract class Infer { /** throw a type error if arguments not within bounds. */ - public 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), "[", ",", "]")); - } - } + public abstract void checkBounds(Symbol[] tparams, Type[] targs, String prefix); - /** Instantiate variable to glb of its high bounds. - */ - private void maximizeVar(Type tp) { - switch (tp) { - case TypeVar(Type origin, Type.Constraint constr): - if (constr.inst == Type.NoType) - constr.inst = Type.glb(constr.hibounds.toArray()); - break; - default: - throw new ApplicationError(); - } - } - - /** Instantiate variable to lub of its low bounds. - */ - private void minimizeVar(Type tp) { - switch (tp) { - case TypeVar(Type origin, Type.Constraint constr): - if (constr.inst == Type.NoType) - constr.inst = Type.lub(constr.lobounds.toArray()); - break; - default: - throw new ApplicationError(); - } - } - - /** Solve constraint collected in types `tvars', instantiating `tvars[i]' - * in the process. - * @param tparams The type parameters corresponding to `tvars' - * @param upper When `true' search for max solution else min. - * @param variances The variances of type parameters; need to reverse - * solution direction for all contravariant variables. - * @param tvars All type variables to be instantiated. - * @param i The index of the type variable to be instantiated. - */ - private void solve(Symbol[] tparams, boolean upper, int[] variances, Type[] tvars, int i) - throws NoInstance { - if (tvars[i] != Type.NoType) { - switch (tvars[i]) { - case TypeVar(Type origin, Type.Constraint constr): - if (constr.inst != Type.NoType) { - constr.inst = tvars[i] = instantiate(constr.inst); - } else { - Type tvar = tvars[i]; - boolean up = (variances[i] != CONTRAVARIANT) ? upper - : !upper; - tvars[i] = Type.NoType; - Type bound = up ? tparams[i].info() : tparams[i].loBound(); - boolean cyclic = false; - for (int j = 0; j < tvars.length; j++) { - if (bound.contains(tparams[j]) || - up && tparams[j].loBound().isSameAs(tparams[i].type()) || - !up && tparams[j].info().isSameAs(tparams[i].type())) { - cyclic |= tvars[j] == Type.NoType; - solve(tparams, upper, variances, tvars, j); - } - } - if (!cyclic) { - if (up) { - if (bound.symbol() != Global.instance.definitions.ANY_CLASS) - constr.hibounds = new Type.List( - bound.subst(tparams, tvars), constr.hibounds); - for (int j = 0; j < tvars.length; j++) { - if (tparams[j].loBound().isSameAs( - tparams[i].type())) { - constr.hibounds = new Type.List( - tparams[j].type().subst(tparams, tvars), - constr.hibounds); - } - } - } else { - if (bound.symbol() != Global.instance.definitions.ALL_CLASS) - constr.lobounds = new Type.List( - bound.subst(tparams, tvars), constr.lobounds); - for (int j = 0; j < tvars.length; j++) { - if (tparams[j].info().isSameAs( - tparams[i].type())) { - constr.lobounds = new Type.List( - tparams[j].type().subst(tparams, tvars), - constr.lobounds); - } - } - } - } - if (up) maximizeVar(tvar); - else minimizeVar(tvar); - tvars[i] = ((Type.TypeVar) tvar).constr.inst; - } - } - } - } - - /** Generate an array of fresh type variables corresponding to parameters - * `tparams' - */ - 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): - Type restp1 = apply(restp); - Symbol[] tparams1 = Symbol.EMPTY_ARRAY; - Symbol[] newparams1 = Symbol.EMPTY_ARRAY; - switch (restp1) { - case PolyType(_, _): - // If there is a nested polytype, we need to - // substitute also its new type parameters for its old ones - // here. Reason: The outer polytype may refer to type - // variables of the inner one. - tparams1 = restp.typeParams(); - newparams1 = restp1.typeParams(); - } - 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) - .subst(tparams1, newparams1)); - newparams[i].setLoBound( - newparams[i].loBound() - .subst(tparams, newparams) - .subst(tparams1, newparams1)); - } - return Type.PolyType( - newparams, restp1.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) { - switch (tp) { - case MethodType(Symbol[] params, Type restype): - return global.definitions.FUNCTION_TYPE( - Symbol.type(params), normalize(restype)); - case PolyType(Symbol[] tparams, Type restype): - if (tparams.length == 0) return normalize(restype); - } - return tp; - } - - /** Is normalized type `tp' a subtype of prototype `pt'? - */ - public boolean isCompatible(Type tp, Type pt) { - Type tp1 = normalize(tp); - if (tp1.isSubType(pt)) return true; - Symbol coerceMeth = tp1.lookup(Names.coerce); - if (coerceMeth.kind == NONE) return false; - return canCoerce(tp1.memberType(coerceMeth), pt); - } - // where - private boolean canCoerce(Type tp, Type pt) { - switch (tp) { - case OverloadedType(_, Type[] alttypes): - for (int i = 0; i < alttypes.length; i++) - if (canCoerce(alttypes[i], pt)) return true; - return false; - case PolyType(Symbol[] tparams, Type restype): - return tparams.length == 0 && restype.isSubType(pt); - default: - return false; - } - } - - public boolean isCompatible(Type[] tps, Type[] pts) { - for (int i = 0; i < tps.length; i++) - if (!isCompatible(tps[i], pts[i])) return false; - return true; - } - - /** Type arguments mapped to `scala.All' are taken to be uninstantiated. - * Map all those type arguments to their corresponding type parameters - * and return all these type parameters as result. - */ - private Symbol[] normalizeArgs(Type[] targs, Symbol[] tparams) { - Type.List uninstantiated = Type.List.EMPTY; - for (int i = 0; i < targs.length; i++) { - if (targs[i].symbol() == Global.instance.definitions.ALL_CLASS) { - 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 minimal type variables exist that make the - * instantiated type a subtype of `pt', return `null'. - */ - private Type[] exprTypeArgs(Symbol[] tparams, Type restype, Type pt) { - Type[] tvars = freshVars(tparams); - Type insttype = restype.subst(tparams, tvars); - if (isCompatible(insttype, pt)) { - try { - restype = normalize(restype); - for (int i = 0; i < tvars.length; i++) { - solve(tparams, false, variance(tparams, restype), tvars, i); - } - return tvars; - } catch (NoInstance ex) { - } - } - return null; - } - - /** Return inferred proto-type arguments of function, given - * its type and value parameters and result type, and a - * prototype `pt' for the function result. - * Type arguments need to be either determined precisely by - * the prototype, or they are maximized, if they occur only covariantly - * in the value parameter list. - * If instantiation of a type parameter fails, - * take Type.AnyType for the proto-type argument. - */ - 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]; - for (int i = 0; i < tvars.length; i++) targs[i] = Type.AnyType; - if (isCompatible(insttype, pt)) { - try { - for (int i = 0; i < tvars.length; i++) { - targs[i] = instantiateToBound( - tvars[i], variance(tparams[i], params)); - } - } catch (NoInstance ex) { - for (int i = 0; i < tvars.length; i++) targs[i] = Type.AnyType; - } - } - return targs; - } - - /** Return inferred type arguments, given type parameters, formal parameters, - * argument types, result type and expected result type. - * If this is not possible, throw a `NoInstance' exception, or, if - * `needToSucceed' is false alternatively return `null'. - * Undetermined type arguments are represented by `definitions.ALL_TYPE'. - * No check that inferred parameters conform to their bounds is made here. - */ - private Type[] methTypeArgs(Symbol[] tparams, - Symbol[] params, Type[] argtypes, - Type restp, Type pt, - 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 = formalTypes(params, argtypes.length); - if (formals.length != argtypes.length) { - if (needToSucceed) - throw new NoInstance("parameter lists differ in length"); - return null; - } - - // check first whether type variables can be fully defined from - // expected result type. - if (!isCompatible(restp.subst(tparams, tvars), pt)) { - if (needToSucceed) - throw new NoInstance("result type " + restp + - " is incompatible with expected type " + pt); - return null; - } - for (int i = 0; i < tvars.length; i++) { - Type.TypeVar tvar = (Type.TypeVar) tvars[i]; - if (!isFullyDefined(tvar)) tvar.constr.inst = Type.NoType; - } - - // Then define remaining type variables from argument types. - for (int i = 0; i < argtypes.length; i++) { - if (!isCompatible(argtypes[i].widen().subst(tparams, tvars), - formals[i].subst(tparams, tvars))) { - if (needToSucceed) { - if (global.explaintypes) { - Type.explainSwitch = true; - argtypes[i].widen().subst(tparams, tvars).isSubType( - formals[i].subst(tparams, tvars)); - Type.explainSwitch = false; - } - throw new NoInstance( - typeErrorMsg( - "argument expression's type is not compatible with formal parameter type", - argtypes[i].widen().subst(tparams, tvars), - formals[i].subst(tparams, tvars))); - } - return null; - } - } - for (int i = 0; i < tvars.length; i++) { - solve(tparams, false, variance(tparams, formals), tvars, i); - } - //System.out.println(" = " + ArrayApply.toString(tvars));//DEBUG - return tvars; - } - - /** 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) { - //System.out.println("tpar " + tparams[i] + " of " + tparams[i].owner() + " <> " + sym);//DEBUG - //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 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 attempts fail, a Type.Error is thrown. - */ - public 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 = exprTypeArgs(tparams, restype, pt1); - if (targs == null) - targs = exprTypeArgs(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); - } - } - } - - /** Instantiate expression `tree' of polymorphic type [tparams]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 = exprTypeArgs(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 [tparams]restype, - * so that resulting method type can be applied to arguments with - * types `argtypes' and its result type is compatible with `pt'. - */ - public Tree methodInstance(Tree tree, - Symbol[] tparams, Type restype, - Type[] argtypes, 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 methodInstance(tree, tparams2, restype1, argtypes, pt); - case MethodType(Symbol[] params, Type restpe): - Type[] targs; - try { - targs = methTypeArgs(tparams, params, argtypes, restpe, pt, true); - } catch (NoInstance ex) { - throw new Type.Error( - applyErrorMsg( - "no type parameters for ", tree, - " exist so that it can be applied to arguments ", - Type.widen(argtypes), 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, Type.PolyType(uninstantiated, restpe)); - return mkTypeApply(tree, tparams, restype1, targs); - default: - return tree; - } - } - - /** Instantiate constructor `tree' of polymorphic type [tparams]restype', - * so that its the result type of `restype' matches prototype `pt'. - * If constructor is polymorphic, maximize all type variables under this - * condition. - */ - 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)) { - try { - for (int i = 0; i < tvars.length; i++) { - solve(tparams, true, variance(tparams, restype.resultType()), - tvars, i); - } - checkBounds(tparams, tvars, "inferred "); - tree.setType(restype.subst(tparams, tvars)); - //System.out.println("inferred constructor type: " + tree.type);//DEBUG - } catch (NoInstance ex) { - throw new Type.Error( - "constructor of type " + ctpe1 + - " can be instantiated in more than one way to expected type " + - pt + - "\n --- because ---\n" + ex.getMessage()); - } - } 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'? - */ - public boolean isApplicable(Type ftpe, Type[] argtypes, Type pt) { - switch (ftpe) { - case MethodType(Symbol[] params, Type restpe): - // sequences ? List( a* ) - Type[] formals = formalTypes(params, argtypes.length); - return - isCompatible(restpe, pt) && - formals.length == argtypes.length && - isCompatible(argtypes, formals); - case PolyType(Symbol[] tparams, MethodType(Symbol[] params, Type restpe)): - try { - Type[] targs = methTypeArgs( - tparams, params, argtypes, restpe, pt, false); - if (targs != null) { - Symbol[] uninstantiated = normalizeArgs(targs, tparams); - return - isWithinBounds(tparams, targs) && - exprTypeArgs(uninstantiated, restpe.subst(tparams, targs), pt) - != null; - } - } catch (NoInstance ex) { - } - } - return false; - } - - /** Does type `ftpe1' specialize 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 { - // first, catch the case of a missing parameter - // list for an overloaded constructor. - if (alts.length > 0) { - int i = 0; - while (i < alts.length && - alts[i].isConstructor() && - alttypes[i] instanceof Type.MethodType) - i++; - if (i == alts.length) - throw new Type.Error("missing arguments for " + alts[0]); - } - // second, do the normal case. - int best = -1; - for (int i = 0; i < alttypes.length; i++) { - if (isCompatible(alttypes[i], pt) && - (best < 0 || improves(alttypes[i], alttypes[best], pt))) { - best = i; - } - } - for (int i = 0; i < alttypes.length; i++) { - if (isCompatible(alttypes[i], pt) && - (best < 0 || improves(alttypes[i], alttypes[best], pt))) { - 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], pt)) { - throw new Type.Error(overloadResolveErrorMsg( - alts[best], alttypes[best], alts[i], alttypes[i]) + - " expected type " + pt); - } - } - tree.setSymbol(alts[best]).setType(alttypes[best]); - } - } - //where - private boolean improves(Type tp1, Type tp2, Type pt) { - return - !normalize(tp2).isSubType(pt) && normalize(tp1).isSubType(pt) || - tp2.isParameterized() && - (!tp1.isParameterized() || specializes(tp1, 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, - * try to select method with pt = AnyType. - * If pt is AnyType, 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]) + - " argument types " + - ArrayApply.toString(argtypes, "(", ",", ")") + - ((pt == Type.AnyType) ? "" - : " and expected result type " + pt)); - } - } - tree.setSymbol(alts[best]).setType(alttypes[best]); - } else if (pt != Type.AnyType) { - methodAlternative(tree, alts, alttypes, argtypes, Type.AnyType); - } - } - - /** Assign `tree' the type of unique polymorphic alternative with `nparams' - * as the number of type parameters, if it exists. - * Throw error if several such 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[j].isValue() && - alttypes[j].typeParams().length == nparams) - throw new Type.Error(overloadResolveErrorMsg( - alts[i], alttypes[i], alts[j], alttypes[j]) + - " polymorphic function with " + nparams + " parameters"); - } - tree.setSymbol(alts[i]).setType(alttypes[i]); - } - } } - |