private void CheckMatchingMethodForConsistency(MethodInfo matchingMethod, FunctionObject func, int i, int n){
// return-type consistency - the return-type has to be the same
IReflect rir = func.ReturnType(null);
IReflect mrir = matchingMethod is JSFieldMethod ? ((JSFieldMethod)matchingMethod).func.ReturnType(null) : matchingMethod.ReturnType;
if (!rir.Equals(mrir)){
func.funcContext.HandleError(JSError.DifferentReturnTypeFromBase, func.name, true);
return;
}
//Special treatment for methods that implement interface methods
if (func.implementedIface != null){
func.implementedIfaceMethod = matchingMethod;
this.superMembers[i] = func.name; //obliterate it so that it does not show up as unimplemented
return;
}
// visibility consistency - the visibility specification has to be the same
MethodAttributes visibility = func.attributes & MethodAttributes.MemberAccessMask;
if ((matchingMethod.Attributes & MethodAttributes.MemberAccessMask) != visibility)
//Allow Family to match FamORAssem
if ((matchingMethod.Attributes & MethodAttributes.MemberAccessMask) != MethodAttributes.FamORAssem || visibility != MethodAttributes.Family)
func.funcContext.HandleError(JSError.CannotChangeVisibility);
// hiding, overriding and layout consistency
// if i >= 0 after this, the base method is an overridden abstract method and steps should be taken to prevent a not implemented error
if (func.noVersionSafeAttributeSpecified){ // current method does not specify any attribute (i.e. hide or override)
if (this.Engine.versionSafe){
//Give a message. The compiler option requires a method to say hide or override when there is a match.
if ((matchingMethod.Attributes & MethodAttributes.Abstract) != 0){ // base is abstract
func.funcContext.HandleError(JSError.HidesAbstractInBase, this.name + "." + func.name);
func.attributes &= ~MethodAttributes.NewSlot;
//Recover from error by overriding, it may be less bad than throwing a class load exception
}else{
func.funcContext.HandleError(JSError.NewNotSpecifiedInMethodDeclaration, this.IsInTheSameCompilationUnit(matchingMethod));
i = -1;
}
}else{
//No message, override if possible, otherwise hide
if ((matchingMethod.Attributes & MethodAttributes.Virtual) == 0 ||
(matchingMethod.Attributes & MethodAttributes.Final) != 0){ // base is non virtual or final, hide
i = -1;
}else{
func.attributes &= ~MethodAttributes.NewSlot; //override
if ((matchingMethod.Attributes & MethodAttributes.Abstract) == 0)
i = -1;
}
}
}else{ //Current method is marked override or hide
if ((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.ReuseSlot){ // current method specifies override
if ((matchingMethod.Attributes & MethodAttributes.Virtual) == 0 ||
(matchingMethod.Attributes & MethodAttributes.Final) != 0){ // base is non virtual or final, hide
func.funcContext.HandleError(JSError.MethodInBaseIsNotVirtual);
i = -1;
}else{
func.attributes &= ~MethodAttributes.NewSlot; //override
if ((matchingMethod.Attributes & MethodAttributes.Abstract) == 0)
i = -1;
}
}else{ // current method specifies hide
Debug.Assert((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.NewSlot);
if ((matchingMethod.Attributes & MethodAttributes.Abstract) != 0){ // base is abstract
func.funcContext.HandleError(JSError.HidesAbstractInBase, this.name + "." + func.name);
func.attributes &= ~MethodAttributes.NewSlot;
//Recover from error by overriding, it may be less bad than throwing a class load exception
}else
i = -1;
}
}
if (i >= 0){
//Overriding an abstract method. Take steps to prevent error messages.
Debug.Assert((matchingMethod.Attributes & MethodAttributes.Abstract) != 0);
this.superMembers[i] = func.name; //obliterate it so that it does not show up as unimplemented
//Do likewise for any matching abstract members declared in less derived base classes
for (int j = i+1; j < n; j++){ //Most derived class is always first
MemberInfo mem = this.superMembers[j] as MemberInfo;
if (mem == null) continue;
if (mem.Name != matchingMethod.Name) break;
MethodInfo meth2 = mem as MethodInfo;
if (meth2 == null) continue;
if (meth2.IsAbstract && Class.ParametersMatch(meth2.GetParameters(), matchingMethod.GetParameters())){
IReflect rt = matchingMethod is JSFieldMethod ? ((JSFieldMethod)matchingMethod).ReturnIR() : matchingMethod.ReturnType;
IReflect rt2 = meth2 is JSFieldMethod ? ((JSFieldMethod)meth2).ReturnIR() : meth2.ReturnType;
if (rt == rt2) this.superMembers[j] = func.name;
}
}
}
}