summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormihaylov <mihaylov@epfl.ch>2005-07-07 16:22:23 +0000
committermihaylov <mihaylov@epfl.ch>2005-07-07 16:22:23 +0000
commita481860c64304d93b1627a5e089fa490c7b11fc4 (patch)
treed4563637093751d6a9d0e4bef73442440669fb77
parent5e728c60b7eb4bcc7e3a2476a2d5a6947698bfe4 (diff)
downloadscala-a481860c64304d93b1627a5e089fa490c7b11fc4.tar.gz
scala-a481860c64304d93b1627a5e089fa490c7b11fc4.tar.bz2
scala-a481860c64304d93b1627a5e089fa490c7b11fc4.zip
Added delegate support
Credits: Most of the work was done by Martin Rubli as a semester project
-rw-r--r--sources/scala/tools/scalac/typechecker/Analyzer.scala27
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala11
-rw-r--r--sources/scalac/backend/msil/GenMSIL.java73
-rw-r--r--sources/scalac/backend/msil/TypeCreator.java80
-rw-r--r--sources/scalac/symtab/Definitions.java8
-rw-r--r--sources/scalac/symtab/classfile/CLRClassParser.java134
-rw-r--r--sources/scalac/symtab/classfile/CLRTypes.java17
-rw-r--r--sources/scalac/util/Names.java2
8 files changed, 313 insertions, 39 deletions
diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala
index 54236a4a18..790febf143 100644
--- a/sources/scala/tools/scalac/typechecker/Analyzer.scala
+++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala
@@ -616,6 +616,20 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
sym.getType().isInstanceOf[Type$PolyType] &&
sym.typeParams().length == 0;
+ /**
+ * Returns true if the adaption 'from => to' corresponds to a delegate
+ * forward view.
+ *
+ * TODO: The check should probably be deeper than just for a function type
+ * because the user might introduce a view from a delegate type to a
+ * function type himself, which is okay as long as it doesn't collide with
+ * the forward view.
+ */
+ private def isDelegateForwardView(from: Type, to: Type): boolean =
+ definitions.DELEGATE_TYPE() != null &&
+ from.isSubType(definitions.DELEGATE_TYPE()) &&
+ to.isFunctionType();
+
// Views -----------------------------------------------------------------------
private def applyView(v: View, tree: Tree, mode: int, pt: Type): Tree = {
@@ -1646,6 +1660,13 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
case _ =>
}
val v = infer.bestView(tree.getType(), pt, Names.EMPTY);
+ // Convert views of delegate types to closures wrapped around
+ // the expression's apply method.
+ if(global.target == scalac_Global.TARGET_MSIL &&
+ v != null && isDelegateForwardView(tree.getType(), pt)) {
+ val meth: Symbol = tree.symbol().lookup(Names.apply);
+ return adapt(gen.Select(tree, meth), mode, pt);
+ }
if (v != null) return applyView(v, tree, mode, pt);
// todo: remove
val coerceMeth: Symbol = tree.getType().lookup(Names.coerce);
@@ -1814,6 +1835,12 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
}
}
}
+ // MSIL: Forbid chaining of non-variable delegate objects using += and -=
+ if(global.target == scalac_Global.TARGET_MSIL &&
+ qual.getType().isSubType(definitions.DELEGATE_TYPE()) &&
+ (sym.name == Names.PLUSEQ || sym.name == Names.MINUSEQ) &&
+ !qual.symbol().isVariable())
+ error(tree.pos, "illegal modification of non-variable delegate");
val qualtype =
if (qual.isInstanceOf[Tree.Super]) context.enclClass.owner.thisType()
else qual.getType();
diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala
index 0890e3ed52..69b74f8adc 100644
--- a/sources/scala/tools/scalac/typechecker/Infer.scala
+++ b/sources/scala/tools/scalac/typechecker/Infer.scala
@@ -1395,7 +1395,16 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
if (best != null) {
viewMeths = availableViews(tp);
while (!viewMeths.isEmpty) {
- if (viewMeths.head != best &&
+ // Ugly hack necessary for MSIL delegate support
+ // Used to be just:
+ // if (viewMeths.head != best &&
+ // isApplicable(viewMeths.head.symtype, argtypes, pt, name, false) &&
+ // !(specializesView(best.symtype, viewMeths.head.symtype) &&
+ // !specializesView(viewMeths.head.symtype, best.symtype))) {
+ if ((if (global.target == scalac_Global.TARGET_MSIL)
+ viewMeths.head.sym != best.sym
+ else
+ viewMeths.head != best) &&
isApplicable(viewMeths.head.symtype, argtypes, pt, name, false) &&
!(specializesView(best.symtype, viewMeths.head.symtype) &&
!specializesView(viewMeths.head.symtype, best.symtype))) {
diff --git a/sources/scalac/backend/msil/GenMSIL.java b/sources/scalac/backend/msil/GenMSIL.java
index 8aab417000..73535cd3fb 100644
--- a/sources/scalac/backend/msil/GenMSIL.java
+++ b/sources/scalac/backend/msil/GenMSIL.java
@@ -850,10 +850,50 @@ public final class GenMSIL {
genLoad(args[0], convTo);
return items.StackItem(convTo);
}
+ // Generate delegate's reverse view
+ if (sym.name == Names.view &&
+ CLRTypes.instance().isDelegateType(resType.toType()))
+ {
+ assert args.length == 1 : Debug.show(sym);
+ return createDelegateFromFunction(args[0], resType);
+ }
return check(invokeMethod(sym, args, resType, true));
case Select(Tree qualifier, _):
+ // Treat delegate chaining methods += and -= in a special way
+ if(CLRTypes.instance().isDelegateType(tc.getType(qualifier.type())) &&
+ (sym.name == Names.PLUSEQ || sym.name == Names.MINUSEQ)) {
+ Type delegate = tc.getType(qualifier.type());
+ MSILType delegateType = msilType(delegate);
+ MethodBase chainer = tc.getMethod(sym);
+
+ switch(qualifier) {
+ case Apply(Tree f, _):
+ Symbol setterSym = f.symbol().owner().lookup(
+ Name.fromString(f.symbol().name.toString() +
+ Names._EQ));
+ assert !setterSym.isNone() : "Setter method not found";
+ MethodInfo setter = (MethodInfo)tc.getMethod(setterSym);
+
+ // Generate object and argument for the setter call
+ emitThis(); // FIXME: doesn't work if the variable is
+ // is a member of another class
+ genLoad(qualifier, delegateType);
+ invokeMethod(sym, args, delegateType, false);
+ code.Emit(OpCodes.Castclass, delegate);
+ code.Emit(OpCodes.Callvirt, setter);
+ return items.VoidItem();
+
+ case Ident(_):
+ // Prepare the left-hand side for the store
+ Item var = gen(qualifier, delegateType);
+ load(var);
+ invokeMethod(sym, args, delegateType, false);
+ code.Emit(OpCodes.Castclass, delegate);
+ return check(store(var));
+ }
+ }
// scala.Any.==
if (sym == defs.ANY_EQEQ) {
return genEq(qualifier, args[0]);
@@ -1328,12 +1368,39 @@ public final class GenMSIL {
(MethodInfo)method);
res = returnsVoid(method) ? items.VoidItem() : items.StackItem(resType);
}
- if (returnsVoid(fun) && !returnsVoid(method)) {
- res = drop(res);
- }
+ CLRTypes clrt = CLRTypes.instance();
+ if (returnsVoid(fun) && !returnsVoid(method)
+ && method != clrt.DELEGATE_COMBINE
+ && method != clrt.DELEGATE_REMOVE)
+ {
+ res = drop(res);
+ }
return res;
}
+ private Item createDelegateFromFunction(Tree fun, MSILType type) {
+ Item ifun = genLoad(fun, msilType(fun.type));
+ // Get the apply function of the delegate object
+ Symbol funSym = tc.getSymbol(ifun.type.toType());
+ Symbol applySym = funSym.lookup(Names.apply);
+ MethodInfo apply = (MethodInfo) tc.getDelegateApplyMethod(applySym);
+
+ // Get the (object, native int) constructor of the delegate type
+ Type delegateType = type.toType();
+ ConstructorInfo delegCtor = delegateType.GetConstructor(
+ new Type[]{tc.OBJECT, Type.GetType("System.IntPtr")});
+
+ // Duplicate the object on the stack; we need its apply method
+ // and Ldvirtftn uses one element.
+ code.Emit(OpCodes.Dup);
+ code.Emit(OpCodes.Ldvirtftn, apply);
+
+ // Create a new delegate; this uses up the element duplicated above.
+ code.Emit(OpCodes.Newobj, delegCtor);
+
+ return items.StackItem(type);
+ }
+
/*
* Returns the MSILType that corresponds to the given scala.symtab.Type
*/
diff --git a/sources/scalac/backend/msil/TypeCreator.java b/sources/scalac/backend/msil/TypeCreator.java
index f5f036b225..7efa5645b1 100644
--- a/sources/scalac/backend/msil/TypeCreator.java
+++ b/sources/scalac/backend/msil/TypeCreator.java
@@ -714,6 +714,10 @@ final class TypeCreator {
}
}
+ public Symbol getSymbol(Type type) {
+ return (Symbol) types2symbols.get(type);
+ }
+
public Type createType(Symbol clazz) {
try { return createType0(clazz); }
catch (Error e) {
@@ -963,6 +967,82 @@ final class TypeCreator {
return method;
}
+ /**
+ * Returns all MethodBase objects corresponding to the symbol.
+ */
+ private MethodBase[] getMethods(Symbol sym) {
+ MethodBase method = (MethodBase) symbols2methods.get(sym);
+ if (method != null)
+ return new MethodBase[]{method};
+ MemberInfo m = ti.getMember(sym);
+ if (m != null && m instanceof MethodBase) {
+ method = (MethodBase) m;
+ } else {
+ // force the creation of the declaring type
+ Type owner = getType(sym.owner());
+ assert owner != null : Debug.show(sym);
+ method = (MethodBase) symbols2methods.get(sym);
+ if (method != null)
+ return new MethodBase[]{method};
+ switch (sym.info()) {
+ case MethodType(Symbol[] vparams, scalac.symtab.Type result):
+ Type[] params = new Type[vparams.length];
+ Type resType = getType(result);
+ for (int i = 0; i < params.length; i++)
+ params[i] = getType(vparams[i]);
+ if (sym.isInitializer()) {
+ // The owner of a constructor is the outer class
+ // so get the result type of the constructor
+ method = owner.GetConstructor(params);
+ assert method != null : "cannot find " + owner
+ + "::.ctor" + methodSignature(params);
+ } else {
+ method = owner instanceof TypeBuilder
+ ? findMethod(sym.owner(), sym)
+ : owner.GetMethod
+ (getMethodName(sym.name, params), params, resType);
+ }
+ break;
+ case OverloadedType(Symbol[] alts, scalac.symtab.Type[] alttypes):
+ MethodBase[] methods = new MethodBase[alts.length];
+ for (int i = 0; i < alts.length; i++)
+ methods[i] = getMethod(alts[i]);
+ return methods;
+
+ default:
+ throw Debug.abort("Symbol doesn't have a method type", sym);
+ }
+ assert method != null
+ : Debug.show(owner) + " => Cannot find method: " + methodSignature(sym);
+ }
+ symbols2methods.put(sym, method);
+ return new MethodBase[]{method};
+ }
+
+ /**
+ * Returns the exactest apply method.
+ * The exactest method is taken to be the first method that doesn't have
+ * an 'object' return type and all 'object' parameter types.
+ */
+ public MethodBase getDelegateApplyMethod(Symbol sym) {
+ MethodBase methods[] = getMethods(sym);
+ if(methods.length > 1) {
+ assert methods.length == 2;
+ for (int i = 0; i < methods.length; i++) {
+ if(((MethodInfo)methods[i]).ReturnType != OBJECT)
+ return methods[i];
+ ParameterInfo pi[] = methods[i].GetParameters();
+ for (int j = 0; j < pi.length; j++) {
+ if(pi[j].ParameterType != OBJECT)
+ return methods[i];
+ }
+ }
+ throw Debug.abort("Expected apply method not found", sym);
+ } else {
+ return methods[0];
+ }
+ }
+
private String getMethodName(Name name, Type[] params) {
if (name == Names.finalize && params.length == 0)
return "Finalize";
diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java
index 70386c9d1a..bf2fa6fc34 100644
--- a/sources/scalac/symtab/Definitions.java
+++ b/sources/scalac/symtab/Definitions.java
@@ -742,6 +742,12 @@ public class Definitions {
return JAVAREFARRAYTYPE_JAVAREFARRAYTYPE;
}
+ // MSIL delegate types
+ public final Symbol DELEGATE_CLASS;
+ public final Type DELEGATE_TYPE() {
+ return DELEGATE_CLASS != null ? DELEGATE_CLASS.staticType() : null;
+ }
+
//########################################################################
// Public Fields - Global values
@@ -794,6 +800,8 @@ public class Definitions {
STRING_CLASS = getClass(forMSIL ? "System.String" : "java.lang.String");
THROWABLE_CLASS =
getClass(forMSIL ? "System.Exception" : "java.lang.Throwable");
+ // .NET delegate class
+ DELEGATE_CLASS = forMSIL ? getClass("System.MulticastDelegate") : null;
// the scala value classes
UNIT_CLASS = getClass("scala.Unit");
diff --git a/sources/scalac/symtab/classfile/CLRClassParser.java b/sources/scalac/symtab/classfile/CLRClassParser.java
index 92b9409492..498237edbe 100644
--- a/sources/scalac/symtab/classfile/CLRClassParser.java
+++ b/sources/scalac/symtab/classfile/CLRClassParser.java
@@ -133,7 +133,6 @@ public class CLRClassParser extends SymbolLoader {
continue;
assert props[i].PropertyType == getter.ReturnType;
Name n;
- Symbol method;
scalac.symtab.Type mtype;
ParameterInfo[] gparams = getter.GetParameters();
@@ -145,13 +144,8 @@ public class CLRClassParser extends SymbolLoader {
n = Names.apply;
mtype = methodType(getter, getter.ReturnType);
}
- Symbol owner = getter.IsStatic() ? staticsClass : clazz;
int mods = translateAttributes(getter);
- method = owner.newMethod(Position.NOPOS, mods, n);
- setParamOwners(mtype, method);
- method.setInfo(mtype);
- (getter.IsStatic() ? statics : members).enterOrOverload(method);
- clrTypes.map(method, getter);
+ createMethod(n, mods, mtype, getter, getter.IsStatic());
assert methodsSet.contains(getter) : "" + getter;
methodsSet.remove(getter);
@@ -168,12 +162,8 @@ public class CLRClassParser extends SymbolLoader {
else n = Names.update;
mods = translateAttributes(setter);
- method = owner.newMethod(Position.NOPOS, mods, n);
mtype = methodType(setter, global.definitions.UNIT_TYPE());
- setParamOwners(mtype, method);
- method.setInfo(mtype);
- (setter.IsStatic() ? statics : members).enterOrOverload(method);
- clrTypes.map(method, setter);
+ createMethod(n, mods, mtype, setter, setter.IsStatic());
assert methodsSet.contains(setter) : "" + setter;
methodsSet.remove(setter);
}
@@ -186,6 +176,12 @@ public class CLRClassParser extends SymbolLoader {
createMethod(method);
}
+ // Create symbols related to delegate types
+ if(clrTypes.isDelegateType(type)) {
+ createDelegateView();
+ createDelegateChainers();
+ }
+
// for enumerations introduce comparison and bitwise logical operations;
// the backend should recognize and replace them with comparison or
// bitwise logical operations on the primitive underlying type
@@ -197,20 +193,13 @@ public class CLRClassParser extends SymbolLoader {
make.methodType(argTypes,
global.definitions.boolean_TYPE(),
scalac.symtab.Type.EMPTY_ARRAY);
- Symbol enumCmp = clazz.newMethod
- (Position.NOPOS, mods, ENUM_CMP_NAMES[i]);
- setParamOwners(enumCmpType, enumCmp);
- enumCmp.setInfo(enumCmpType);
- members.enterOrOverload(enumCmp);
+ createMethod(ENUM_CMP_NAMES[i], mods, enumCmpType, null, false);
}
for (int i = 0; i < ENUM_BIT_LOG_NAMES.length; i++) {
scalac.symtab.Type enumBitLogType = make.methodType
(argTypes, clazzType, scalac.symtab.Type.EMPTY_ARRAY);
- Symbol enumBitLog = clazz.newMethod
- (Position.NOPOS, mods, ENUM_BIT_LOG_NAMES[i]);
- setParamOwners(enumBitLogType, enumBitLog);
- enumBitLog.setInfo(enumBitLogType);
- members.enterOrOverload(enumBitLog);
+ createMethod
+ (ENUM_BIT_LOG_NAMES[i], mods, enumBitLogType, null, false);
}
}
@@ -239,20 +228,17 @@ public class CLRClassParser extends SymbolLoader {
ICustomAttributeProvider member,
scalac.symtab.Type defaultType)
{
- scalac.symtab.Type symbolType = null;
- if (!member.IsDefined(clrTypes.PICO_META_ATTR, false)) {
- symbolType = defaultType;
- } else {
+ if (member !=null && member.IsDefined(clrTypes.PICO_META_ATTR, false)) {
Object[] attrs =
member.GetCustomAttributes(clrTypes.PICO_META_ATTR, false);
assert attrs.length == 1 : "attrs.length = " + attrs.length;
String meta =
(String)((Attribute)attrs[0]).getConstructorArguments()[0];
- symbolType = new MetaParser
+ defaultType = new MetaParser
(meta, tvars, sym, defaultType, clazz, clazzType, make).parse();
}
- sym.setInfo(symbolType);
- return symbolType;
+ sym.setInfo(defaultType);
+ return defaultType;
}
private void createConstructor(ConstructorInfo constr) {
@@ -278,13 +264,85 @@ public class CLRClassParser extends SymbolLoader {
if (mtype == null)
return;
int mods = translateAttributes(method);
- Symbol owner = method.IsStatic() ? staticsClass : clazz;
- Symbol methodSym =
- owner.newMethod(Position.NOPOS, mods, getName(method));
+ createMethod(getName(method), mods, mtype, method, method.IsStatic());
+ }
+
+ // Create static view methods within the delegate and the function type
+ // with the following signatures:
+ // def MyDelegate.view(MyDelegate): FunctionX[InvokeArgs..., InvokeRet];
+ // def FunctionX.view(FunctionX[InvokeArgs..., InvokeRet]): MyDelegate;
+ private void createDelegateView() {
+ // Extract the parameter and return types of the Invoke method
+ MethodInfo invoke = (MethodInfo)type.GetMember("Invoke")[0];
+ scalac.symtab.Type invokeRetType = getCLRType(invoke.ReturnType);
+ scalac.symtab.Type invokeParamTypes[] =
+ new scalac.symtab.Type[invoke.GetParameters().length];
+ for(int j = 0; j < invoke.GetParameters().length; j++)
+ invokeParamTypes[j] =
+ getCLRType(invoke.GetParameters()[j].ParameterType);
+ scalac.symtab.Type funType =
+ global.definitions.FUNCTION_TYPE(invokeParamTypes, invokeRetType);
+
+ // FORWARD MAPPING (Delegate => Function)
+ scalac.symtab.Type viewParamTypes[] = { getCLRType(type) };
+ scalac.symtab.Type viewRetType = funType;
+ scalac.symtab.Type viewMethodType = make.methodType(
+ viewParamTypes,
+ viewRetType,
+ scalac.symtab.Type.EMPTY_ARRAY);
+
+ createMethod(Names.view, Modifiers.JAVA, viewMethodType, null, true);
+
+ // REVERSE MAPPING (Function => Delegate)
+ viewParamTypes = new scalac.symtab.Type[]{ funType };
+ viewRetType = getCLRType(type);
+ viewMethodType = make.methodType(
+ viewParamTypes,
+ viewRetType,
+ scalac.symtab.Type.EMPTY_ARRAY);
+
+ createMethod(Names.view, Modifiers.JAVA, viewMethodType, null, true);
+ }
+
+ private void createDelegateChainers() {
+ int mods = Modifiers.JAVA | Modifiers.FINAL;
+ Type[] args = new Type[]{type};
+
+ createMethod(Names.PLUSEQ, mods, args, clrTypes.VOID,
+ clrTypes.DELEGATE_COMBINE, false);
+ createMethod(Names.MINUSEQ, mods, args, clrTypes.VOID,
+ clrTypes.DELEGATE_REMOVE, false);
+ createMethod
+ (Names.PLUS, mods, args, type, clrTypes.DELEGATE_COMBINE, false);
+ createMethod
+ (Names.MINUS, mods, args, type, clrTypes.DELEGATE_REMOVE, false);
+ }
+
+ private Symbol createMethod(Name name, int mods, Type[] args,
+ Type retType, MethodInfo method, boolean statik)
+ {
+ return createMethod(name, mods, args, getCLSType(retType), method, statik);
+ }
+ private Symbol createMethod(Name name, int mods, Type[] args,
+ scalac.symtab.Type retType,
+ MethodInfo method,
+ boolean statik)
+ {
+ scalac.symtab.Type mtype = methodType(args, retType);
+ assert mtype != null : name;
+ return createMethod(name, mods, mtype, method, statik);
+ }
+ private Symbol createMethod(Name name, int mods, scalac.symtab.Type mtype,
+ MethodInfo method, boolean statik)
+ {
+ Symbol methodSym = (statik ? staticsClass: clazz)
+ .newMethod(Position.NOPOS, mods, name);
setParamOwners(mtype, methodSym);
- parseMeta(methodSym, method, mtype);
- (method.IsStatic() ? statics : members).enterOrOverload(methodSym);
- clrTypes.map(methodSym, method);
+ parseMeta(methodSym, method, mtype); // sets the type to mtype if no meta
+ (statik ? statics : members).enterOrOverload(methodSym);
+ if (method != null)
+ clrTypes.map(methodSym, method);
+ return methodSym;
}
private Name getName(MethodInfo method) {
@@ -303,6 +361,12 @@ public class CLRClassParser extends SymbolLoader {
// TODO: check if the type implements ICloneable?
if (name.equals("Clone") && params.length == 0)
return Names.clone;
+ // Pretend that delegates have a 'apply' method instead of the 'Invoke'
+ // method. This is harmless because the latter one can't be called
+ // directly anyway.
+ if (name.equals("Invoke")
+ && clrTypes.isDelegateType(method.DeclaringType))
+ return Names.apply;
return Name.fromString(name);
}
diff --git a/sources/scalac/symtab/classfile/CLRTypes.java b/sources/scalac/symtab/classfile/CLRTypes.java
index ab1e8e54c4..d14ba470ed 100644
--- a/sources/scalac/symtab/classfile/CLRTypes.java
+++ b/sources/scalac/symtab/classfile/CLRTypes.java
@@ -65,6 +65,7 @@ public final class CLRTypes {
public final Type BOOLEAN;
public final Type VOID;
public final Type ENUM;
+ public final Type DELEGATE;
public final Type OBJECT;
public final Type STRING;
@@ -78,6 +79,9 @@ public final class CLRTypes {
public final ConstructorInfo SYMTAB_CONSTR;
public final ConstructorInfo SYMTAB_DEFAULT_CONSTR;
+ public final MethodInfo DELEGATE_COMBINE;
+ public final MethodInfo DELEGATE_REMOVE;
+
private final SymbolNameWriter snw = new SymbolNameWriter();
private Type[] types;
@@ -109,6 +113,7 @@ public final class CLRTypes {
BOOLEAN = getType("System.Boolean");
VOID = getType("System.Void");
ENUM = getType("System.Enum");
+ DELEGATE = getType("System.MulticastDelegate");
OBJECT = getType("System.Object");
STRING = getType("System.String");
@@ -123,8 +128,15 @@ public final class CLRTypes {
SYMTAB_DEFAULT_CONSTR =
SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes);
+ Type delegate = Type.GetType("System.Delegate");
+ Type[] dargs = new Type[]{delegate, delegate};
+ DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs);
+ DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs);
+
assert PICO_META_ATTR != null;
assert SCALA_SYMTAB_ATTR != null;
+ assert DELEGATE_COMBINE != null;
+ assert DELEGATE_REMOVE != null;
Type[] types = Type.EmptyTypes;
Iterator as = assemblies.iterator();
@@ -183,6 +195,11 @@ public final class CLRTypes {
return getType(elemType.FullName + "[]");
}
+ // Returns true if the given type is a delegate type.
+ public boolean isDelegateType(Type t) {
+ return t.BaseType() == DELEGATE;
+ }
+
//##########################################################################
// assembly loading methods
diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java
index 9bde7b9b5c..66a67f819c 100644
--- a/sources/scalac/util/Names.java
+++ b/sources/scalac/util/Names.java
@@ -118,6 +118,8 @@ public class Names {
public static final Name AMPAMP = encode("&&");
public static final Name COLONCOLON = encode("::");
public static final Name PERCENT = encode("%");
+ public static final Name PLUSEQ = encode("+=");
+ public static final Name MINUSEQ = encode("-=");
public static final Name All = Name.fromString("All");
public static final Name AllRef = Name.fromString("AllRef");